mini_kraken 0.2.00 → 0.2.01

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bbfe3d58d4c7271a5c8a54486a743c51d6fddcb3b068095cad44cacad575c83
4
- data.tar.gz: 012b412a95752592b5be70859e00d94b379e2c4c564d37d932a300a03cbc9716
3
+ metadata.gz: f51855ac3179a111a4ace328340402fa167818773086076abf90ed845c31d248
4
+ data.tar.gz: f6bde0d3d7b872461d7cb0b087eaab821240f14317445e95f4d832d09af51e2f
5
5
  SHA512:
6
- metadata.gz: 952d93b01de392c7168e7cfb4a3cc911e4d1b53be11a4a10d67012bb4ab4a8f69aa42f41bf13a756f89a6d09eb775a5594174d73334c57c2230039b7991e89fd
7
- data.tar.gz: a60adbd5da627495badab63de355336f131a5e599c40226931366a7c1b4a349b2542ccb55cf30ef8e60990341c1f5d8547804b1552fbbbc504bd1bed40a36d9e
6
+ metadata.gz: ae6319164a2f6212bdbdea35dd5b5befa86648b685063dea79d220b70e5852c3e8b343d2d37ebfe6584aa3966b44174e91df2866d63e03a219a0008a5b382d66
7
+ data.tar.gz: 70eb204ab842ea45527bd5ca8661dcd98081422cae4d6848d220bc70e080da94b3b7078f3602f1143535821a9894309b9bec39ec5f4d6c60edcfd21cfa5c8f4f
@@ -0,0 +1,334 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'exp/**/*'
4
+
5
+ Layout/ArgumentAlignment:
6
+ Enabled: false
7
+
8
+ Layout/ArrayAlignment:
9
+ Enabled: true
10
+ EnforcedStyle: with_fixed_indentation
11
+
12
+ Layout/CaseIndentation:
13
+ Enabled: false
14
+
15
+ Layout/ClosingHeredocIndentation:
16
+ Enabled: false
17
+
18
+ Layout/CommentIndentation:
19
+ Enabled: false
20
+
21
+ Layout/ElseAlignment:
22
+ Enabled: false
23
+
24
+ Layout/EmptyLines:
25
+ Enabled: false
26
+
27
+ Layout/EndAlignment:
28
+ Enabled: false
29
+
30
+ Layout/EndOfLine:
31
+ Enabled: true
32
+ EnforcedStyle: lf
33
+
34
+ Layout/FirstArgumentIndentation:
35
+ Enabled: false
36
+
37
+ Layout/IndentationWidth:
38
+ Enabled: false
39
+
40
+ Layout/IndentationConsistency:
41
+ Enabled: true
42
+
43
+ Layout/HeredocIndentation:
44
+ Enabled: false
45
+
46
+ Layout/MultilineHashBraceLayout:
47
+ Enabled: true
48
+
49
+ Layout/MultilineMethodCallBraceLayout:
50
+ Enabled: true
51
+ EnforcedStyle: same_line
52
+
53
+ Layout/SpaceAroundOperators:
54
+ Enabled: true
55
+
56
+ Layout/SpaceInsideParens:
57
+ Enabled: true
58
+
59
+ Layout/IndentationStyle:
60
+ Enabled: true
61
+
62
+ Layout/SpaceAroundMethodCallOperator:
63
+ Enabled: true
64
+
65
+ Layout/TrailingEmptyLines:
66
+ Enabled: true
67
+
68
+ Layout/TrailingWhitespace:
69
+ Enabled: true
70
+
71
+ Lint/Loop:
72
+ Enabled: true
73
+
74
+ Lint/RaiseException:
75
+ Enabled: true
76
+
77
+ Lint/RescueException:
78
+ Enabled: true
79
+
80
+ Lint/StructNewOverride:
81
+ Enabled: true
82
+
83
+ Lint/UnusedMethodArgument:
84
+ Enabled: true
85
+
86
+ Lint/UselessAccessModifier:
87
+ Enabled: true
88
+
89
+ Lint/Void:
90
+ Enabled: false
91
+
92
+ Lint/UselessAssignment:
93
+ Enabled: true
94
+
95
+ Metrics/AbcSize:
96
+ Enabled: false
97
+
98
+ Metrics/BlockLength:
99
+ Enabled: true
100
+ Max: 350
101
+
102
+ Metrics/BlockNesting:
103
+ Enabled: true
104
+ Max: 5
105
+
106
+ Metrics/ClassLength:
107
+ Enabled: true
108
+ Max: 350
109
+
110
+ Metrics/CyclomaticComplexity:
111
+ Enabled: false
112
+
113
+ Layout/LineLength:
114
+ Enabled: false
115
+ Max: 90
116
+
117
+ Metrics/MethodLength:
118
+ Enabled: true
119
+ Max: 50
120
+
121
+ Metrics/ModuleLength:
122
+ Enabled: true
123
+ Max: 500
124
+
125
+ Metrics/PerceivedComplexity:
126
+ Enabled: false
127
+
128
+ Naming/ConstantName:
129
+ Enabled: false
130
+
131
+ Naming/ClassAndModuleCamelCase:
132
+ Enabled: false
133
+
134
+ Naming/BlockParameterName:
135
+ Enabled: true
136
+
137
+ Naming/MethodParameterName:
138
+ Enabled: false
139
+
140
+ Naming/VariableName:
141
+ Enabled: false
142
+
143
+ Style/Alias:
144
+ Enabled: true
145
+
146
+ Layout/HashAlignment:
147
+ Enabled: false
148
+
149
+ Style/AsciiComments:
150
+ Enabled: false
151
+
152
+ Style/BarePercentLiterals:
153
+ Enabled: false
154
+
155
+ Style/BlockComments:
156
+ Enabled: false
157
+
158
+ Style/CharacterLiteral:
159
+ Enabled: false
160
+
161
+ Style/ClassCheck:
162
+ Enabled: false
163
+
164
+ Style/ClassVars:
165
+ Enabled: false
166
+
167
+ Style/ColonMethodCall:
168
+ Enabled: false
169
+
170
+ Style/CommentAnnotation:
171
+ Enabled: false
172
+
173
+ Style/CommentedKeyword:
174
+ Enabled: false
175
+
176
+ Style/ConditionalAssignment:
177
+ Enabled: false
178
+
179
+ Style/DefWithParentheses:
180
+ Enabled: true
181
+
182
+ Style/Documentation:
183
+ Enabled: false
184
+
185
+ Style/ExpandPathArguments:
186
+ Enabled: false
187
+
188
+ Style/ExponentialNotation:
189
+ Enabled: true
190
+
191
+ Style/GuardClause:
192
+ Enabled: false
193
+
194
+ Style/HashEachMethods:
195
+ Enabled: true
196
+
197
+ Style/HashTransformKeys:
198
+ Enabled: true
199
+
200
+ Style/HashTransformValues:
201
+ Enabled: true
202
+
203
+ Style/IfUnlessModifier:
204
+ Enabled: false
205
+
206
+ Style/InverseMethods:
207
+ Enabled: true
208
+
209
+ Style/MissingRespondToMissing:
210
+ Enabled: false
211
+
212
+ Style/Next:
213
+ Enabled: false
214
+
215
+ Style/NumericLiterals:
216
+ Enabled: false
217
+
218
+ Style/RaiseArgs:
219
+ Enabled: true
220
+
221
+ Style/RedundantReturn:
222
+ Enabled: false
223
+
224
+ Style/RedundantSelf:
225
+ Enabled: true
226
+
227
+ Style/RegexpLiteral:
228
+ Enabled: false
229
+
230
+ Style/PercentLiteralDelimiters:
231
+ Enabled: false
232
+
233
+ Style/StderrPuts:
234
+ Enabled: false
235
+
236
+ Style/StringLiterals:
237
+ Enabled: true
238
+
239
+ Style/TernaryParentheses:
240
+ Enabled: false
241
+
242
+ Style/UnlessElse:
243
+ Enabled: false
244
+
245
+ # Rubocop complains when it doesn't find an explicit setting for the following cops:
246
+ Layout/EmptyLinesAroundAttributeAccessor:
247
+ Enabled: true
248
+
249
+ Lint/BinaryOperatorWithIdenticalOperands:
250
+ Enabled: true
251
+
252
+ Lint/DeprecatedOpenSSLConstant:
253
+ Enabled: true
254
+
255
+ Lint/DuplicateElsifCondition:
256
+ Enabled: true
257
+
258
+ Lint/DuplicateRescueException:
259
+ Enabled: true
260
+
261
+ Lint/EmptyConditionalBody:
262
+ Enabled: true
263
+
264
+ Lint/FloatComparison:
265
+ Enabled: true
266
+
267
+ Lint/MissingSuper:
268
+ Enabled: true
269
+
270
+ Lint/MixedRegexpCaptureTypes:
271
+ Enabled: true
272
+
273
+ Lint/OutOfRangeRegexpRef:
274
+ Enabled: true
275
+
276
+ Lint/SelfAssignment:
277
+ Enabled: true
278
+
279
+ Lint/TopLevelReturnWithArgument:
280
+ Enabled: true
281
+
282
+ Lint/UnreachableLoop:
283
+ Enabled: true
284
+
285
+ Style/AccessorGrouping:
286
+ Enabled: true
287
+
288
+ Style/ArrayCoercion:
289
+ Enabled: true
290
+
291
+ Style/BisectedAttrAccessor:
292
+ Enabled: true
293
+
294
+ Style/CaseLikeIf:
295
+ Enabled: true
296
+
297
+ Style/ExplicitBlockArgument:
298
+ Enabled: true
299
+
300
+ Style/GlobalStdStream:
301
+ Enabled: true
302
+
303
+ Style/HashAsLastArrayItem:
304
+ Enabled: true
305
+
306
+ Style/HashLikeCase:
307
+ Enabled: true
308
+
309
+ Style/OptionalBooleanParameter:
310
+ Enabled: true
311
+
312
+ Style/RedundantAssignment:
313
+ Enabled: true
314
+
315
+ Style/RedundantFetchBlock:
316
+ Enabled: true
317
+
318
+ Style/RedundantFileExtensionInRequire:
319
+ Enabled: true
320
+
321
+ Style/RedundantRegexpCharacterClass:
322
+ Enabled: true
323
+
324
+ Style/RedundantRegexpEscape:
325
+ Enabled: true
326
+
327
+ Style/SingleArgumentDig:
328
+ Enabled: true
329
+
330
+ Style/SlicingWithRange:
331
+ Enabled: true
332
+
333
+ Style/StringConcatenation:
334
+ Enabled: true
@@ -1,3 +1,12 @@
1
+ ## [0.2.01] - 2020-08-07
2
+ - The DSL (Domain Specific Language) now supports `defrel` and boolean literals.
3
+
4
+ ### CHANGED
5
+ - Constructor `DefRelation#initialize` now freezes any new class instance.
6
+ - Constructor `GoalTemplate#initialize` now freezes any new class instance.
7
+ - Mixin module `Core::DSL` new method `defrel` to build custom relations.
8
+ - File `.rubocop.yml` to please Rubocop 0.89
9
+
1
10
  ## [0.2.00] - 2020-07-12
2
11
  - First release of DSL (Domain Specific Language)
3
12
  - Fix defect for fused variables that remain fresh
data/README.md CHANGED
@@ -30,12 +30,12 @@ ISBN: 9780262535519, (2018), MIT Press.
30
30
  - [ ] Occurs check
31
31
 
32
32
  List-centric relations from Chapter 2
33
- - [ ] caro
34
- - [ ] cdro
35
- - [ ] conso
36
- - [ ] nullo
37
- - [ ] pairo
38
- - [ ] singletono
33
+ - [ ] caro
34
+ - [ ] cdro
35
+ - [ ] conso
36
+ - [ ] nullo
37
+ - [ ] pairo
38
+ - [ ] singletono
39
39
 
40
40
  ## Installation
41
41
 
@@ -73,9 +73,9 @@ The two first lines in the above code snippet are pretty standard:
73
73
  - The first line loads the `mini_kraken` library.
74
74
  - The second line add the DSL methods to the current object.
75
75
 
76
- The next line constitutes a trivial `miniKanren` program.
77
- The aim of a `miniKanren` program is to find one or more solutions involving provided variable(s)
78
- and satisfying one or more goals.
76
+ The next line constitutes a trivial `miniKanren` program.
77
+ The aim of a `miniKanren` program is to find one or more solutions involving the given logical variable(s)
78
+ and satisfying one or more goals to the `run_star method.
79
79
  In our example, the `run_star` method instructs `MiniKraken` to find all solutions,
80
80
  knowing that each successful solution:
81
81
  - binds a value to the provided variable `q` and
@@ -101,7 +101,8 @@ So the above program succeeds and the only found solution is obtained by binding
101
101
  puts result # => ()
102
102
  ```
103
103
  In this example, we learn that `run_star` can take multiple goals placed in an array.
104
- The program fails to find a solution since it is not possible to satisfy the two `equals` goals simultaneously. In that case, the `run_star` return an empty list represented as `()` in the output.
104
+ The program fails to find a solution since it is not possible to satisfy the two `equals` goals simultaneously.
105
+ In case of failure, the `run_star` returns an empty list represented as `()` in the output.
105
106
 
106
107
 
107
108
  ### Example 3
@@ -127,7 +128,8 @@ This time, `run_star` takes two logical variables -`x` and `y`- and successfully
127
128
  puts result # => ((:blue :sea) (:blue :mountain) (:red :sea) (:red :mountain))
128
129
  ```
129
130
 
130
- Here, `run_star` takes two logical variables and two `disj2` goals. A `disj2` succeeds if any of its arguments succeeds.
131
+ Here, `run_star` takes two logical variables and two `disj2` goals.
132
+ A `disj2` succeeds if any of its arguments succeeds.
131
133
  This program finds four distinct solutions for x, y pairs.
132
134
 
133
135
  ## Development
@@ -13,6 +13,7 @@ module MiniKraken
13
13
 
14
14
  # @param aValue [Object] Ruby representation of MiniKraken data value
15
15
  def initialize(aValue)
16
+ super()
16
17
  @value = aValue
17
18
  @value.freeze
18
19
  end
@@ -10,6 +10,7 @@ unless MiniKraken::Core.constants(false).include? :ConsCell
10
10
  attr_reader :cdr
11
11
 
12
12
  def initialize(obj1, obj2 = nil)
13
+ super()
13
14
  @car = obj1
14
15
  if obj2.kind_of?(ConsCell) && obj2.null?
15
16
  @cdr = nil
@@ -19,6 +19,7 @@ module MiniKraken
19
19
  super(aName, alternateName)
20
20
  @formals = validated_formals(theFormals)
21
21
  @goal_template = validated_goal_template(aGoalTemplate)
22
+ freeze
22
23
  end
23
24
 
24
25
  # Number of arguments for the relation.
@@ -60,7 +60,7 @@ module MiniKraken
60
60
  return unless descendent.successful?
61
61
 
62
62
  vars.each_key do |var_name|
63
- assocs = descendent[var_name]
63
+ # assocs = descendent[var_name]
64
64
  move_assocs(var_name, descendent)
65
65
  end
66
66
  end
@@ -38,10 +38,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
38
38
  return result
39
39
  end
40
40
  new_arg1, new_arg2 = commute_cond(arg1, arg2, anEnv)
41
- result = do_unification(new_arg1, new_arg2, anEnv)
42
- # anEnv.merge(result) if result.successful? && !result.association.empty?
43
-
44
- result
41
+ do_unification(new_arg1, new_arg2, anEnv)
45
42
  end
46
43
 
47
44
  private
@@ -141,7 +138,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
141
138
  total_success = subresults.all?(&:successful?)
142
139
  if total_success
143
140
  memo = Outcome.success(anEnv)
144
- associations = subresults.reduce(memo) do |sub_total, outcome|
141
+ subresults.reduce(memo) do |sub_total, outcome|
145
142
  sub_total.merge(outcome)
146
143
  sub_total
147
144
  end
@@ -11,6 +11,7 @@ module MiniKraken
11
11
  attr_reader :name
12
12
 
13
13
  def initialize(aName)
14
+ super()
14
15
  @name = validated_name(aName)
15
16
  end
16
17
 
@@ -16,6 +16,7 @@ module MiniKraken
16
16
  # @param aRelation [Relation] The relation corresponding to this goal
17
17
  # @param args [Array<Term>] The actual aguments of the goal
18
18
  def initialize(aRelation, args)
19
+ super()
19
20
  @relation = aRelation
20
21
  @actuals = validated_actuals(args)
21
22
  end
@@ -35,7 +36,7 @@ module MiniKraken
35
36
  raise StandardError, err_msg
36
37
  end
37
38
 
38
- prefix = "Invalid goal argument '"
39
+ prefix = 'Invalid goal argument'
39
40
  args.each do |actual|
40
41
  if actual.kind_of?(GoalArg) || actual.kind_of?(Environment)
41
42
  next
@@ -43,7 +44,7 @@ module MiniKraken
43
44
  validated_actuals(actual)
44
45
  else
45
46
  actual_display = actual.nil? ? 'nil' : actual.to_s
46
- raise StandardError, prefix + actual_display + "'"
47
+ raise StandardError, "#{prefix} '#{actual_display}'"
47
48
  end
48
49
  end
49
50
 
@@ -8,15 +8,17 @@ module MiniKraken
8
8
  # The individual goals are instantiated when the formal arguments
9
9
  # are bound to goal arguments
10
10
  class GoalTemplate < BaseArg
11
- # @return [Array<BaseArg>}] Arguments of goal template.
11
+ # @return [Array<BaseArg>] Arguments of goal template.
12
12
  attr_reader :args
13
13
 
14
14
  # @return [Relation] Main relation for the goal template
15
15
  attr_reader :relation
16
16
 
17
17
  def initialize(aRelation, theArgs)
18
+ super()
18
19
  @relation = validated_relation(aRelation)
19
20
  @args = validated_args(theArgs)
21
+ freeze
20
22
  end
21
23
 
22
24
  # @param formals [Array<FormalArg>] Array of formal arguments
@@ -20,7 +20,7 @@ module MiniKraken
20
20
 
21
21
  # Returns a string representing the MiniKraken symbol.
22
22
  def to_s
23
- ':' + id2name
23
+ ":#{id2name}"
24
24
  end
25
25
  end # class
26
26
  end # module
@@ -13,6 +13,7 @@ module MiniKraken
13
13
 
14
14
  # @param aName [String] The name of the variable
15
15
  def initialize(aName)
16
+ super()
16
17
  init_designation(aName)
17
18
  end
18
19
 
@@ -1,11 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
3
4
  require_relative '../core/any_value'
4
5
  require_relative '../core/conj2'
5
6
  require_relative '../core/cons_cell'
7
+ require_relative '../core/def_relation'
6
8
  require_relative '../core/disj2'
7
9
  require_relative '../core/equals'
8
10
  require_relative '../core/fail'
11
+ require_relative '../core/formal_arg'
12
+ require_relative '../core/formal_ref'
13
+ require_relative '../core/goal_template'
14
+ require_relative '../core/k_boolean'
9
15
  require_relative '../core/k_symbol'
10
16
  require_relative '../core/succeed'
11
17
  require_relative '../core/variable_ref'
@@ -15,31 +21,64 @@ require_relative 'run_star_expression'
15
21
 
16
22
  module MiniKraken
17
23
  module Glue
24
+ # The mixin module that implements the methods for the DSL
25
+ # (DSL = Domain Specific Langague) that allows MiniKraken
26
+ # users to embed Minikanren in their Ruby code.
18
27
  module DSL
28
+ # A run* expression tries to find all the solutions
29
+ # that meet the given goal.
19
30
  # @return [Core::ConsCell] A list of solutions
20
31
  def run_star(var_names, goal)
21
32
  program = RunStarExpression.new(var_names, goal)
22
33
  program.run
23
34
  end
24
35
 
36
+ # conj2 stands for conjunction of two arguments.
37
+ # Returns a goal linked to the Core::Conj2 relation.
38
+ # The rule of that relation succeeds when both arguments succeed.
39
+ # @param arg1 [Core::Goal]
40
+ # @param arg2 [Core::Goal]
41
+ # @return [Core::Failure|Core::Success]
25
42
  def conj2(arg1, arg2)
26
- Core::Goal.new(Core::Conj2.instance, [convert(arg1), convert(arg2)])
43
+ goal_class.new(Core::Conj2.instance, [convert(arg1), convert(arg2)])
27
44
  end
28
45
 
29
46
  def cons(car_item, cdr_item = nil)
30
- Core::ConsCell.new(convert(car_item), convert(cdr_item))
47
+ tail = cdr_item.nil? ? cdr_item : convert(cdr_item)
48
+ Core::ConsCell.new(convert(car_item), tail)
49
+ end
50
+
51
+ def defrel(relationName, theFormals, &aGoalTemplateExpr)
52
+ start_defrel
53
+
54
+ case theFormals
55
+ when String
56
+ @defrel_formals << theFormals
57
+ when Array
58
+ @defrel_formals.merge(theFormals)
59
+ end
60
+
61
+ formals = @defrel_formals.map { |name| Core::FormalArg.new(name) }
62
+ g_template = aGoalTemplateExpr.call
63
+ result = Core::DefRelation.new(relationName, g_template, formals)
64
+ add_defrel(result)
65
+
66
+ end_defrel
67
+ result
31
68
  end
32
69
 
33
70
  def disj2(arg1, arg2)
34
- Core::Goal.new(Core::Disj2.instance, [convert(arg1), convert(arg2)])
71
+ goal_class.new(Core::Disj2.instance, [convert(arg1), convert(arg2)])
35
72
  end
36
73
 
74
+ # @return [Core::Fail] A goal that unconditionally fails.
37
75
  def _fail
38
- Core::Goal.new(Core::Fail.instance, [])
76
+ goal_class.new(Core::Fail.instance, [])
39
77
  end
40
78
 
41
79
  def equals(arg1, arg2)
42
- Core::Goal.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
80
+ # require 'debug'
81
+ goal_class.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
43
82
  end
44
83
 
45
84
  def fresh(var_names, goal)
@@ -47,19 +86,30 @@ module MiniKraken
47
86
 
48
87
  if var_names.kind_of?(String) || var_names.kind_of?(Core::VariableRef)
49
88
  vars = [var_names]
50
- elsif
51
-
89
+ else
52
90
  vars = var_names
53
91
  end
92
+
54
93
  FreshEnv.new(vars, goal)
55
94
  end
56
95
 
96
+ def list(*members)
97
+ return null if members.empty?
98
+
99
+ head = nil
100
+ members.reverse_each { |elem| head = Core::ConsCell.new(convert(elem), head) }
101
+
102
+ head
103
+ end
104
+
105
+ # @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
57
106
  def null
58
107
  Core::ConsCell.new(nil, nil)
59
108
  end
60
109
 
110
+ # @return [Core::Succeed] A goal that unconditionally succeeds.
61
111
  def succeed
62
- Core::Goal.new(Core::Succeed.instance, [])
112
+ goal_class.new(Core::Succeed.instance, [])
63
113
  end
64
114
 
65
115
  private
@@ -74,27 +124,83 @@ module MiniKraken
74
124
  any_val = Core::AnyValue.allocate
75
125
  any_val.instance_variable_set(:@rank, rank)
76
126
  converted = any_val
127
+ elsif anArgument.id2name =~ /^"#[ft]"$/
128
+ converted = Core::KBoolean.new(anArgument)
77
129
  else
78
130
  converted = Core::KSymbol.new(anArgument)
79
131
  end
132
+ when String
133
+ if anArgument =~ /^#[ft]$/
134
+ converted = Core::KBoolean.new(anArgument)
135
+ else
136
+ msg = "Internal error: undefined conversion for #{anArgument.class}"
137
+ raise StandardError, msg
138
+ end
139
+ when false, true
140
+ converted = Core::KBoolean.new(anArgument)
141
+ when Core::KBoolean
142
+ converted = anArgument
143
+ when Core::FormalRef
144
+ converted = anArgument
80
145
  when Core::Goal
81
146
  converted = anArgument
147
+ when Core::GoalTemplate
148
+ converted = anArgument
82
149
  when Core::VariableRef
83
150
  converted = anArgument
84
151
  when Core::ConsCell
85
152
  converted = anArgument
153
+ else
154
+ msg = "Internal error: undefined conversion for #{anArgument.class}"
155
+ raise StandardError, msg
86
156
  end
87
157
 
88
158
  converted
89
159
  end
90
160
 
161
+ def default_mode
162
+ @dsl_mode = :default
163
+ @defrel_formals = nil
164
+ end
165
+
166
+ def goal_class
167
+ default_mode unless instance_variable_defined?(:@dsl_mode)
168
+ @dsl_mode == :default ? Core::Goal : Core::GoalTemplate
169
+ end
170
+
171
+ def start_defrel
172
+ @dsl_mode = :defrel
173
+ @defrel_formals = Set.new
174
+ end
175
+
176
+ def end_defrel
177
+ default_mode
178
+ end
179
+
180
+ def add_defrel(aDefRelation)
181
+ @defrels = {} unless instance_variable_defined?(:@defrels)
182
+ @defrels[aDefRelation.name] = aDefRelation
183
+ end
184
+
91
185
  def method_missing(mth, *args)
92
186
  result = nil
93
187
 
94
188
  begin
95
189
  result = super(mth, *args)
96
190
  rescue NameError
97
- result = Core::VariableRef.new(mth.id2name)
191
+ name = mth.id2name
192
+ @defrels = {} unless instance_variable_defined?(:@defrels)
193
+ if @defrels.include?(name)
194
+ def_relation = @defrels[name]
195
+ result = Core::Goal.new(def_relation, args.map { |el| convert(el) })
196
+ else
197
+ default_mode unless instance_variable_defined?(:@dsl_mode)
198
+ if @dsl_mode == :defrel && @defrel_formals.include?(name)
199
+ result = Core::FormalRef.new(name)
200
+ else
201
+ result = Core::VariableRef.new(name)
202
+ end
203
+ end
98
204
  end
99
205
 
100
206
  result
@@ -38,11 +38,9 @@ module MiniKraken
38
38
 
39
39
  # @return [Array] A vector of assignment for each variable
40
40
  def build_solution(outcome)
41
- sol = env.vars.values.map do |var|
41
+ env.vars.values.map do |var|
42
42
  outcome.successful? ? var.quote(outcome) : nil
43
43
  end
44
-
45
- sol
46
44
  end
47
45
 
48
46
  # Transform the solutions into sequence of conscells.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniKraken
4
- VERSION = '0.2.00'
4
+ VERSION = '0.2.01'
5
5
  end
@@ -9,6 +9,7 @@ module PkgExtending
9
9
  def self.pkg_files(aPackage)
10
10
  file_list = Dir[
11
11
  '.rspec',
12
+ '.rubocop.yml',
12
13
  '.travis.yml',
13
14
  'Gemfile',
14
15
  'Rakefile',
@@ -19,7 +20,8 @@ module PkgExtending
19
20
  'bin/*.rb',
20
21
  'lib/*.*',
21
22
  'lib/**/*.rb',
22
- 'spec/**/*.rb'
23
+ 'spec/**/*.rb',
24
+ 'spec/.rubocop.yml'
23
25
  ]
24
26
  aPackage.files = file_list
25
27
  aPackage.test_files = Dir['spec/**/*_spec.rb']
@@ -38,8 +40,8 @@ Gem::Specification.new do |spec|
38
40
  spec.authors = ['Dimitri Geshef']
39
41
  spec.email = ['famished.tiger@yahoo.com']
40
42
 
41
- spec.summary = %q{Implementation of Minikanren language in Ruby. WIP}
42
- spec.description = %q{Implementation of Minikanren language in Ruby. WIP}
43
+ spec.summary = 'Implementation of Minikanren language in Ruby. WIP'
44
+ spec.description = 'Implementation of Minikanren language in Ruby. WIP'
43
45
  spec.homepage = 'https://github.com/famished-tiger/mini_kraken'
44
46
  spec.license = 'MIT'
45
47
 
@@ -47,6 +49,7 @@ Gem::Specification.new do |spec|
47
49
  spec.bindir = 'exe'
48
50
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
49
51
  spec.require_paths = ['lib']
52
+ spec.required_ruby_version = '~> 2.4'
50
53
 
51
54
  PkgExtending.pkg_files(spec)
52
55
  PkgExtending.pkg_documentation(spec)
@@ -0,0 +1,13 @@
1
+ inherit_from: ../.rubocop.yml
2
+
3
+ # RSpec expectation lines can be very lenghty
4
+ Layout/LineLength:
5
+ Max: 99
6
+
7
+ # RSpec contexts can be very lenghty
8
+ Metrics/BlockLength:
9
+ Max: 1000
10
+
11
+ # RSpec modules can be very lenghty
12
+ Metrics/ModuleLength:
13
+ Max: 1000
@@ -52,7 +52,7 @@ module MiniKraken
52
52
  outcome1 = instance1.resume
53
53
 
54
54
  instance2 = DuckFiber.new(:success)
55
- outcome2 = instance1.resume
55
+ outcome2 = instance2.resume
56
56
 
57
57
  expect(outcome1).not_to be_equal(outcome2)
58
58
  end
@@ -65,7 +65,7 @@ module MiniKraken
65
65
  # Default Ruby representation, different value
66
66
  expect(subject == :pod).to be_falsy
67
67
  end
68
-
68
+
69
69
  it 'should provide a string representation of itself' do
70
70
  expect(subject.to_s).to eq(':pea')
71
71
  end
@@ -68,7 +68,7 @@ module MiniKraken
68
68
  expect(result.car).to eq(:_0)
69
69
  end
70
70
 
71
- it 'passes frame 1:21' do
71
+ it "supports 'fresh' and passes frame 1:21" do
72
72
  # Reasoned S2, frame 1:21
73
73
  # (run* q (fresh (x) (== 'pea q))) ;; => (pea)
74
74
 
@@ -176,7 +176,7 @@ module MiniKraken
176
176
  expect(result.car).to eq(cons(:_0, cons(:_1, cons(:_0))))
177
177
  end
178
178
 
179
- it 'passes frame 1:50' do
179
+ it "supports 'conj2' relation and passes frame 1:50" do
180
180
  # Reasoned S2, frame 1:50
181
181
  # (run* q (conj2 succeed succeed)) ;; => (_0)
182
182
 
@@ -216,7 +216,7 @@ module MiniKraken
216
216
  expect(result.car).to eq(:corn)
217
217
  end
218
218
 
219
- it 'passes frame 1:55' do
219
+ it "supports 'disj2' and passes frame 1:55" do
220
220
  # Reasoned S2, frame 1:55
221
221
  # (run* q (disj2 fail fail)) ;; => ()
222
222
 
@@ -301,7 +301,7 @@ module MiniKraken
301
301
  # (== 'oil x))))) ;; => (olive _0 oil)
302
302
 
303
303
  result = run_star('x', disj2(conj2(equals(:virgin, x), _fail),
304
- disj2(equals(:olive, x), disj2(succeed, equals(:oil, x)))))
304
+ disj2(equals(:olive, x), disj2(succeed, equals(:oil, x)))))
305
305
  expect(result).to eq(cons(:olive, cons(:_0, cons(:oil))))
306
306
  end
307
307
 
@@ -317,8 +317,8 @@ module MiniKraken
317
317
  # (== '(,x ,y) r)))))) ;; => ((split pea))
318
318
 
319
319
  result = run_star('r', fresh('x', fresh('y',
320
- conj2(equals(:split, x), conj2(
321
- equals(:pea, y), equals(cons(x, cons(y)), r))))))
320
+ conj2(equals(:split, x),
321
+ conj2(equals(:pea, y), equals(cons(x, cons(y)), r))))))
322
322
  expect(result).to eq(cons(cons(:split, cons(:pea))))
323
323
  end
324
324
 
@@ -396,8 +396,7 @@ module MiniKraken
396
396
  # (== 'pea y))) ;; => ((split pea))
397
397
 
398
398
  result = run_star(%w[x y], conj2(equals(:split, x), equals(:pea, y)))
399
- expect(result.car.car).to eq(:split)
400
- expect(result.car.cdr.car).to eq(:pea)
399
+ expect(result.car).to eq(list(:split, :pea))
401
400
  end
402
401
 
403
402
  it 'passes frame 1:76' do
@@ -410,10 +409,8 @@ module MiniKraken
410
409
  result = run_star(%w[x y], disj2(
411
410
  conj2(equals(:split, x), equals(:pea, y)),
412
411
  conj2(equals(:red, x), equals(:bean, y))))
413
- expect(result.car.car).to eq(:split)
414
- expect(result.car.cdr.car).to eq(:pea)
415
- expect(result.cdr.car.car).to eq(:red)
416
- expect(result.cdr.car.cdr.car).to eq(:bean)
412
+ expect(result.car).to eq(list(:split, :pea))
413
+ expect(result.cdr.car).to eq(list(:red, :bean))
417
414
  end
418
415
 
419
416
  it 'passes frame 1:77' do
@@ -432,12 +429,8 @@ module MiniKraken
432
429
  conj2(equals(:split, x), equals(:pea, y)),
433
430
  conj2(equals(:red, x), equals(:bean, y))),
434
431
  equals(cons(x, cons(y, cons(:soup))), r))))
435
- expect(result.car.car).to eq(:split)
436
- expect(result.car.cdr.car).to eq(:pea)
437
- expect(result.car.cdr.cdr.car).to eq(:soup)
438
- expect(result.cdr.car.car).to eq(:red)
439
- expect(result.cdr.car.cdr.car).to eq(:bean)
440
- expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
432
+ expect(result.car).to eq(list(:split, :pea, :soup))
433
+ expect(result.cdr.car).to eq(list(:red, :bean, :soup))
441
434
  end
442
435
 
443
436
  it 'passes frame 1:78' do
@@ -451,15 +444,11 @@ module MiniKraken
451
444
 
452
445
  result = run_star('r',
453
446
  fresh(%w[x y], [disj2(
454
- conj2(equals(:split, x), equals(:pea, y)),
455
- conj2(equals(:red, x), equals(:bean, y))),
447
+ conj2(equals(:split, x), equals(:pea, y)),
448
+ conj2(equals(:red, x), equals(:bean, y))),
456
449
  equals(cons(x, cons(y, cons(:soup))), r)]))
457
- expect(result.car.car).to eq(:split)
458
- expect(result.car.cdr.car).to eq(:pea)
459
- expect(result.car.cdr.cdr.car).to eq(:soup)
460
- expect(result.cdr.car.car).to eq(:red)
461
- expect(result.cdr.car.cdr.car).to eq(:bean)
462
- expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
450
+ expect(result.car).to eq(list(:split, :pea, :soup))
451
+ expect(result.cdr.car).to eq(list(:red, :bean, :soup))
463
452
  end
464
453
 
465
454
  it 'passes frame 1:80' do
@@ -471,15 +460,11 @@ module MiniKraken
471
460
  # (== 'soup z)) ;; => ((split pea soup) (red bean soup))
472
461
 
473
462
  result = run_star(%w[x y z], [disj2(
474
- conj2(equals(:split, x), equals(:pea, y)),
475
- conj2(equals(:red, x), equals(:bean, y))),
476
- equals(:soup, z)])
477
- expect(result.car.car).to eq(:split)
478
- expect(result.car.cdr.car).to eq(:pea)
479
- expect(result.car.cdr.cdr.car).to eq(:soup)
480
- expect(result.cdr.car.car).to eq(:red)
481
- expect(result.cdr.car.cdr.car).to eq(:bean)
482
- expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
463
+ conj2(equals(:split, x), equals(:pea, y)),
464
+ conj2(equals(:red, x), equals(:bean, y))),
465
+ equals(:soup, z)])
466
+ expect(result.car).to eq(list(:split, :pea, :soup))
467
+ expect(result.cdr.car).to eq(list(:red, :bean, :soup))
483
468
  end
484
469
 
485
470
  it 'passes frame 1:81' do
@@ -489,8 +474,119 @@ module MiniKraken
489
474
  # (== 'pea y)) ;; => ((split pea))
490
475
 
491
476
  result = run_star(%w[x y], [equals(:split, x), equals(:pea, y)])
492
- expect(result.car.car).to eq(:split)
493
- expect(result.car.cdr.car).to eq(:pea)
477
+ expect(result.car).to eq(list(:split, :pea))
478
+ end
479
+
480
+ it "supports 'defrel' and passes frame 1:82" do
481
+ # Reasoned S2, frame 1:82
482
+ # (defrel (teacupo t)
483
+ # (disj2 (== 'tea t) (== 'cup t)))
484
+
485
+ result = defrel('teacupo', 't') do
486
+ disj2(equals(:tea, t), equals(:cup, t))
487
+ end
488
+
489
+ expect(result).to be_kind_of(Core::DefRelation)
490
+ expect(result.name).to eq('teacupo')
491
+ expect(result.formals.size).to eq(1)
492
+ expect(result.formals[0].name).to eq('t')
493
+ g_template = result.goal_template
494
+ expect(g_template).to be_kind_of(Core::GoalTemplate)
495
+ expect(g_template.relation).to eq(Core::Disj2.instance)
496
+
497
+ first_arg = g_template.args[0]
498
+ expect(first_arg).to be_kind_of(Core::GoalTemplate)
499
+ expect(first_arg.relation).to eq(Core::Equals.instance)
500
+ expect(first_arg.args[0]).to eq(:tea)
501
+ expect(first_arg.args[1]).to be_kind_of(Core::FormalRef)
502
+ expect(first_arg.args[1].name).to eq('t')
503
+ second_arg = g_template.args[1]
504
+ expect(second_arg).to be_kind_of(Core::GoalTemplate)
505
+ expect(second_arg.relation).to eq(Core::Equals.instance)
506
+ expect(second_arg.args[0]).to eq(:cup)
507
+ expect(second_arg.args[1]).to be_kind_of(Core::FormalRef)
508
+ expect(second_arg.args[1].name).to eq('t')
509
+ end
510
+
511
+ def defrel_teacupo
512
+ defrel('teacupo', 't') { disj2(equals(:tea, t), equals(:cup, t)) }
513
+ end
514
+
515
+ it "supports the invokation of a 'defrel' and passes frame 1:83" do
516
+ # Reasoned S2, frame 1:83
517
+ # (run* x
518
+ # (teacupo x)) ;; => ((tea cup))
519
+
520
+ defrel_teacupo
521
+ result = run_star('x', teacupo(x))
522
+
523
+ expect(result).to eq(cons(:tea, cons(:cup)))
524
+ end
525
+
526
+ it 'supports booleans and passes frame 1:84' do
527
+ # Reasoned S2, frame 1:84
528
+ # (run* (x y)
529
+ # (disj2
530
+ # (conj2 (teacupo x) (== #t y))
531
+ # (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
532
+
533
+ defrel_teacupo
534
+ result = run_star(%w[x y],
535
+ disj2(
536
+ conj2(teacupo(x), equals('#t', y)),
537
+ conj2(equals('#f', x), equals('#t', y))))
538
+
539
+ # Order of solutions differs from RS book
540
+ expect(result.car).to eq(cons(:tea, cons(true)))
541
+ expect(result.cdr.car).to eq(cons(:cup, cons(true)))
542
+ expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
543
+ end
544
+
545
+ it 'passes frame 1:85' do
546
+ # Reasoned S2, frame 1:85
547
+ # (run* (x y)
548
+ # (teacupo x)
549
+ # (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
550
+
551
+ defrel_teacupo
552
+ result = run_star(%w[x y], [teacupo(x), teacupo(y)])
553
+
554
+ expect(result.car).to eq(cons(:tea, cons(:tea)))
555
+ expect(result.cdr.car).to eq(cons(:tea, cons(:cup)))
556
+ expect(result.cdr.cdr.car).to eq(cons(:cup, cons(:tea)))
557
+ expect(result.cdr.cdr.cdr.car).to eq(cons(:cup, cons(:cup)))
558
+ end
559
+
560
+ it 'passes frame 1:86' do
561
+ # Reasoned S2, frame 1:86
562
+ # (run* (x y)
563
+ # (teacupo x)
564
+ # (teacupo x)) ;; => ((tea _0)(cup _0))
565
+
566
+ defrel_teacupo
567
+ result = run_star(%w[x y], [teacupo(x), teacupo(x)])
568
+
569
+ expect(result.car).to eq(cons(:tea, cons(:_0)))
570
+ expect(result.cdr.car).to eq(cons(:cup, cons(:_0)))
571
+ end
572
+
573
+ it 'passes frame 1:87' do
574
+ # Reasoned S2, frame 1:87
575
+ # (run* (x y)
576
+ # (disj2
577
+ # (conj2 (teacupo x) (teacupo x))
578
+ # (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
579
+
580
+ defrel_teacupo
581
+ result = run_star(%w[x y], disj2(
582
+ conj2(teacupo(x), teacupo(x)),
583
+ conj2(equals('#f', x), teacupo(y))))
584
+
585
+ # Order of solutions differs from RS book
586
+ expect(result.car).to eq(cons(:tea, cons(:_0)))
587
+ expect(result.cdr.car).to eq(cons(:cup, cons(:_0)))
588
+ expect(result.cdr.cdr.car).to eq(cons(false, cons(:tea)))
589
+ expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(:cup)))
494
590
  end
495
591
  end # context
496
592
  end # describe
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_kraken
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.00
4
+ version: 0.2.01
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-12 00:00:00.000000000 Z
11
+ date: 2020-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -61,6 +61,7 @@ extra_rdoc_files:
61
61
  - README.md
62
62
  files:
63
63
  - ".rspec"
64
+ - ".rubocop.yml"
64
65
  - ".travis.yml"
65
66
  - CHANGELOG.md
66
67
  - Gemfile
@@ -109,6 +110,7 @@ files:
109
110
  - lib/mini_kraken/glue/run_star_expression.rb
110
111
  - lib/mini_kraken/version.rb
111
112
  - mini_kraken.gemspec
113
+ - spec/.rubocop.yml
112
114
  - spec/core/association_spec.rb
113
115
  - spec/core/association_walker_spec.rb
114
116
  - spec/core/conde_spec.rb
@@ -146,9 +148,9 @@ require_paths:
146
148
  - lib
147
149
  required_ruby_version: !ruby/object:Gem::Requirement
148
150
  requirements:
149
- - - ">="
151
+ - - "~>"
150
152
  - !ruby/object:Gem::Version
151
- version: '0'
153
+ version: '2.4'
152
154
  required_rubygems_version: !ruby/object:Gem::Requirement
153
155
  requirements:
154
156
  - - ">="