mini_kraken 0.3.01 → 0.3.02

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: 184cc99bd7696eb4f51fea822e74c98f42396f92cd47e1ce4501bed4cbb6a3c0
4
- data.tar.gz: eb0bad624831f6643db7ec04265424cab58a9245f7fbfd472041e1eaa095de68
3
+ metadata.gz: aef8d438d839320f5a38af687cfef1e4018a687d5a9b3d071f5a485fa03cab3d
4
+ data.tar.gz: a8aefa5c850913634dbe5b28bec9c605782ef2ef7e8791632a9f7b504937442d
5
5
  SHA512:
6
- metadata.gz: 3803703fc02bda7cee5cd72f511f1a4a32bfecb85663571c1b15f002ab82b7551e49654aea9ce3a12e06ffa7c4839999c9ae4df9ce3fd2f9ba679ff827d47541
7
- data.tar.gz: 88bb32e2140526ee415542421ffad57ed768b67995c0a6d70b6c33d46f520b05ee312081b6d8a13ca64042ef004b0e7e2cf8baccbc226f385d0d67776220ac05
6
+ metadata.gz: 521fefadf00ba08606646afdd5f881a1a7bd4626221085c69adc2e822a2c2777b6fa28d71ea5f6541c614e0b8e9ca8470cab2301683d1c9f235bb1e3535f20f3
7
+ data.tar.gz: 99478f83ad99813aa29d82cef6cc5b8ad3d5df376d56819151ecc508d62f0a0fd23a62a1fb3553f8aa231e8c317ad5aa6930503b2cd8ff2951b6d94ca8b3480c
@@ -1,3 +1,13 @@
1
+ ## [0.3.02] - 2020-12-19
2
+ - `mini_kraken` now implements `conso` relation.
3
+
4
+ ### CHANGED
5
+ - Method `Context#build_solution` old source code (redundant) removed.
6
+ - File `README.md` minor changes.
7
+
8
+ ### FIXED
9
+ - Method `ConsCell#expand` pushed a node in the stack even if it was fully visited.
10
+
1
11
  ## [0.3.01] - 2020-12-17
2
12
  - Minor: updated Rubocop config file `.rubocop.yml`
3
13
 
data/README.md CHANGED
@@ -14,10 +14,10 @@ ISBN: 9780262535519, (2018), MIT Press.
14
14
  - Pure Ruby implementation, not a port from another language
15
15
  - Object-Oriented design
16
16
  - No runtime dependencies
17
- - Test suite patterned on the examples from the reference book.
17
+ - Test suite patterned on examples from the reference book.
18
18
 
19
19
  ### miniKanren Features
20
- - [X] ==
20
+ - [X] ( == ) unify
21
21
  - [X] run\*
22
22
  - [X] fresh
23
23
  - [X] conde
@@ -26,13 +26,13 @@ ISBN: 9780262535519, (2018), MIT Press.
26
26
  - [X] defrel
27
27
  - [X] caro
28
28
  - [X] cdro
29
+ - [X] conso
29
30
 
30
31
  ### TODO
31
32
 
32
33
  - [ ] Occurs check
33
34
 
34
- List-centric relations from Chapter 2
35
- - [ ] conso
35
+ Pair-centric relations from Chapter 2
36
36
  - [ ] nullo
37
37
  - [ ] pairo
38
38
  - [ ] singletono
@@ -179,7 +179,7 @@ module MiniKraken
179
179
  new_cell = ConsCell.null
180
180
  if curr_cell
181
181
  curr_cell.set!(side, new_cell)
182
- path.push(curr_cell)
182
+ path.push(curr_cell) unless side == :cdr
183
183
  end
184
184
  curr_cell = new_cell
185
185
  head ||= new_cell
@@ -239,138 +239,6 @@ module MiniKraken
239
239
  # Returns a Hash with pairs of the form:
240
240
  # { String => Association }, or
241
241
  # { String => AnyValue }
242
- def build_zolution
243
- clear_ranking
244
- calc_ranking
245
- solution = {}
246
- return solution if failure?
247
-
248
- # require 'debug'
249
- symbol_table.root.defns.each_pair do |nm, item|
250
- next unless item.kind_of?(LogVar)
251
-
252
- if failure?
253
- solution[nm] = nil
254
- next
255
- end
256
- i_name = item.i_name
257
- assocs = blackboard.associations_for(i_name, true)
258
- if assocs.nil? || assocs.empty? ||
259
- (blackboard.fused?(i_name) && assocs.empty?)
260
- solution[nm] = AnyValue.new(ranking[i_name])
261
- else
262
- my_assocs = []
263
- assocs.each { |a| my_assocs << a if a.kind_of?(Association) }
264
- next if my_assocs.empty?
265
-
266
- # TODO: if multiple associations, conj2 them...
267
- as = my_assocs.first
268
-
269
- deps = as.dependencies(self)
270
- if deps.any? { |i_name_dep| ranking.include? i_name_dep }
271
- # At least one dependent variable in expression is unbound
272
- solution[nm] = substitute(as)
273
- else
274
- solution[nm] = as.value
275
- end
276
- end
277
- end
278
- # Take into current scope (e.g. x).
279
- # e.g. if q depends on other inner scope variable,
280
- # then one should replace every occurrence of x by AnyValue
281
-
282
- solution
283
- end
284
- =begin
285
- find a solution for 1:67
286
- Scope picture:
287
- s_a:
288
- q
289
- ----
290
- s_b:
291
- x
292
- ----
293
- s_c:
294
- y
295
-
296
- Move_queue
297
- bk(s_b)
298
- bk(s_c)
299
- assoc x => :split
300
- assoc y => :pea
301
- assoc r => '(,x ,y)
302
-
303
- Let solution be a Hash i_name => value expression
304
- Let substitutions be a Hash i_name => value expression
305
- Start with root variables:
306
- For each root variable:
307
- Given q:
308
- Is it unbound? N
309
- Is it fused? N
310
- Get its association (Assumption: one association only)
311
- q => '( ,x ,y)
312
- dependents:
313
- Set { x, y}
314
- Given x:
315
- Is it unbound? N
316
- Is it fused? N
317
- Get its association
318
- x => :split
319
- no dependents => pinned, not a root variable:
320
- Add x => :split in substitution
321
- substitution = { x => :split }
322
- Given y:
323
- Is it unbound? N
324
- Is it fused? N
325
- Get its association
326
- y => :pea
327
- no dependents => pinned, not a root variable:
328
- Add y => :pea in substitution
329
- substitution = { x => :split, y => :pea }
330
- All dependents resolved? Y
331
- Add q => (:split :pea) to solution
332
- Done with root variables?
333
- Return solution: q => (split :pea)
334
-
335
- Let solution be a Hash i_name => value expression
336
- Let substitutions be a Hash i_name => value expression
337
- Method add_substitution_for(q, substitutions):
338
- Is it already present in substitutions, then return
339
-
340
- Is it unbound? N
341
- Is it fused? N
342
- Get its association (Assumption: one association only)
343
- Assume q => '( ,x ,y)
344
- with dependents: Set { x, y}
345
- foreach dependent variable call
346
- add_substitution_for(q, substitutions) # Recursive call
347
- no dependents => pinned
348
- Add association in substitution
349
-
350
- IDEA: placeholder in term expressions
351
- '( ,x ,y) is translated into:
352
- cons(placeholder_100(nil), placeholder_200(nil))
353
- x => [placeholder_100]
354
- y => [placeholder_200]
355
-
356
- class Placeholder {
357
- subj = nil
358
- def object_id ; subj.object_id ; end
359
- def kind_of? ; subj.kind_of? ; end
360
- def to_s ; subj.to_s ; end
361
- }
362
-
363
- Where are placedholders created?
364
- - In Association.new
365
-
366
- Do we really need Placeholder?
367
- Do LogVarRef not fill the bill?
368
- IDEA: at a given moment, a LogVarRef is instructed to refer to a value
369
- Difficulty: A variable can take multiple values
370
- Thus the logVarRef may not embed the value but refer to a value indexed by solution.
371
-
372
- =end
373
-
374
242
  def build_solution
375
243
  solution = {}
376
244
  return solution if failure?
@@ -19,7 +19,7 @@ module MiniKraken
19
19
  # When that object receives the message resume, it will
20
20
  # return a success context.
21
21
  # @param _actuals [Array] MUST be empty array for nullary relation.
22
- # @param _ctx [Core::Context] Runtime context
22
+ # @param ctx [Core::Context] Runtime context
23
23
  # @return [Core::DuckFiber]
24
24
  def solver_for(_actuals, ctx)
25
25
  # Important: every `solver_for` call will result in a distinct Context.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniKraken
4
- VERSION = '0.3.01'
4
+ VERSION = '0.3.02'
5
5
  end
@@ -31,11 +31,15 @@ module MiniKraken
31
31
  end
32
32
  end # context
33
33
 
34
- context 'Initialization:' do
34
+ context 'Provided services:' do
35
35
  def var(aName)
36
36
  LogVar.new(aName)
37
37
  end
38
38
 
39
+ def cons(term1, term2 = nil)
40
+ Composite::ConsCell.new(term1, term2)
41
+ end
42
+
39
43
  it 'should accept the addition of an entry in symbol table' do
40
44
  subject.insert(var('x'))
41
45
  expect(subject.symbol_table).not_to be_empty
@@ -189,7 +193,7 @@ module MiniKraken
189
193
  expect(subject.send(:substitute, assoc_q).to_s).to eq('(_0 :foo . :bar)')
190
194
  end
191
195
 
192
- it 'should build a solution' do
196
+ it 'should build a solution (atomic terms)' do
193
197
  subject.add_vars(%w[x y z])
194
198
 
195
199
  subject.succeeded!
@@ -215,6 +219,26 @@ module MiniKraken
215
219
  expect(sol['y']).to eq(bar)
216
220
  expect(sol['z']).to eq(:_0)
217
221
  end
222
+
223
+ it 'should build a solution (composite terms)' do
224
+ subject.add_vars(['l'])
225
+ new_scope = Scope.new
226
+ subject.enter_scope(new_scope)
227
+ a = k_symbol(:a)
228
+ b = k_symbol(:b)
229
+ c = k_symbol(:c)
230
+ subject.add_vars(['d'])
231
+ d_ref = LogVarRef.new('d')
232
+ subject.associate('l', cons(cons(a, cons(b)), d_ref))
233
+ subject.associate('d', cons(c))
234
+
235
+ subject.succeeded!
236
+ sol = subject.build_solution
237
+ expect(sol.size).to eq(1)
238
+
239
+ # TODO: fix next line. Actual is: ((a :c))
240
+ expect(sol['l'].to_s).to eq('((:a :b) :c)')
241
+ end
218
242
  end
219
243
  end # describe
220
244
  end # module
@@ -231,14 +231,14 @@ module MiniKraken
231
231
  # (cdro p d))
232
232
 
233
233
  # As 'p' has a special meaning in Ruby, the argument has been remaned to 'r'
234
- conso_rel = defrel('conso', %w[a r d], [caro(r, a), cdro(r, d)])
234
+ conso_rel = defrel('conso', %w[a d r], [caro(r, a), cdro(r, d)])
235
235
 
236
236
  expect(conso_rel).to be_kind_of(Rela::DefRelation)
237
237
  expect(conso_rel.name).to eq('conso')
238
238
  expect(conso_rel.arity).to eq(3)
239
239
  expect(conso_rel.formals[0]).to match(/^a_[-0-9a-f]+$/)
240
- expect(conso_rel.formals[1]).to match(/^r_[-0-9a-f]+$/)
241
- expect(conso_rel.formals[2]).to match(/^d_[-0-9a-f]+$/)
240
+ expect(conso_rel.formals[1]).to match(/^d_[-0-9a-f]+$/)
241
+ expect(conso_rel.formals[2]).to match(/^r_[-0-9a-f]+$/)
242
242
  g_template = conso_rel.expression
243
243
  expect(g_template.relation).to be_kind_of(Rela::Conj2)
244
244
  g1 = g_template.actuals[0]
@@ -255,7 +255,7 @@ module MiniKraken
255
255
  end
256
256
 
257
257
  # In Scheme:
258
- # (defrel (conso a p d)
258
+ # (defrel (conso a d p)
259
259
  # (caro p a)
260
260
  # (cdro p d))
261
261
  # In Ruby, `p`is a standard Kernel method => replace it by `r`
@@ -263,19 +263,87 @@ module MiniKraken
263
263
  defrel_caro
264
264
  defrel_cdro
265
265
 
266
- defrel('conso', %w[a r d], [caro(r, a), cdro(r, d)])
266
+ # Definition derived from frame 2:25
267
+ # defrel('conso', %w[a d r], [caro(r, a), cdro(r, d)])
268
+
269
+ # Definition derived from frame 2:26
270
+ defrel('conso', %w[a d r], [unify(cons(a, d), r)])
271
+ end
272
+
273
+ it 'passes frame 2:19' do
274
+ defrel_conso
275
+
276
+ # (run* l
277
+ # (conso '(a b c) '(d e) l)) ;; => (((a b c) d e))
278
+
279
+ result = run_star('l', conso(list(:a, :b, :c), list(:d, :e), l))
280
+ expect(result.to_s).to eq('(((:a :b :c) :d :e))')
281
+ end
282
+
283
+ it 'passes frame 2:20' do
284
+ defrel_conso
285
+
286
+ # (run* x
287
+ # (conso x '(a b c) '(d a b c))) ;; => (d)
288
+
289
+ result = run_star('x', conso(x, list(:a, :b, :c), list(:d, :a, :b, :c)))
290
+ expect(result.to_s).to eq('(:d)')
291
+ end
292
+
293
+ it 'passes frame 2:21' do
294
+ defrel_conso
295
+
296
+ # (run* r
297
+ # (fresh (x y z)
298
+ # (== '(e a d ,x) r)
299
+ # (conso y '(a ,z c) r))) ;; => ((e a d c)
300
+
301
+ expr = fresh(%w[x y z],
302
+ [unify(list(:e, :a, :d, x), r),
303
+ conso(y, list(:a, z, :c), r)])
304
+ result = run_star('r', expr)
305
+ expect(result.to_s).to eq('((:e :a :d :c))')
306
+ end
307
+
308
+ it 'passes frame 2:22' do
309
+ defrel_conso
310
+
311
+ # (run* x
312
+ # (conso x '(a ,x c) '(d a ,x c))) ;; => (d)
313
+
314
+ result = run_star('x', conso(x, list(:a, x, :c), list(:d, :a, x, :c)))
315
+ expect(result.to_s).to eq('(:d)')
267
316
  end
268
317
 
269
- # TODO: FIX THIS EXAMPLE
270
- # it 'passes frame 2:19' do
271
- # defrel_conso
318
+ it 'passes frame 2:23' do
319
+ defrel_conso
272
320
 
273
- # # (run* l
274
- # # (conso '(a b c) '(d e) l)) ;; => ((abc) (d e))
321
+ # (run* l
322
+ # (fresh (x)
323
+ # (== '(d a ,x c) l)
324
+ # (conso x '(a ,x c) l))) ;; => ((d a d c)
325
+
326
+ expr = fresh(%w[x],
327
+ [unify(list(:d, :a, x, :c), l),
328
+ conso(x, list(:a, x, :c), l)])
329
+ result = run_star('l', expr)
330
+ expect(result.to_s).to eq('((:d :a :d :c))')
331
+ end
332
+
333
+ it 'passes frame 2:24' do
334
+ defrel_conso
275
335
 
276
- # result = run_star('l', conso( list(:a, :b, :c), list(:d, :e), l))
277
- # expect(result.to_s).to eq('((:a :b :c) (:d :e))')
278
- # end
336
+ # (run* l
337
+ # (fresh (x)
338
+ # (conso x '(a ,x c) l)))
339
+ # (== '(d a ,x c) l) ;; => ((d a d c)
340
+
341
+ expr = fresh(%w[x],
342
+ [conso(x, list(:a, x, :c), l),
343
+ unify(list(:d, :a, x, :c), l)])
344
+ result = run_star('l', expr)
345
+ expect(result.to_s).to eq('((:d :a :d :c))')
346
+ end
279
347
  end # context
280
348
  end # describe
281
349
  end # module
@@ -80,7 +80,7 @@ module MiniKraken
80
80
 
81
81
  # @return [Core::Goal]
82
82
  def fresh(names, subgoal)
83
- puts "#{__callee__} #{names}"
83
+ # puts "#{__callee__} #{names}"
84
84
  if names.kind_of?(Array)
85
85
  k_names = names.map { |nm| Atomic::KString.new(nm) }
86
86
  else
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.3.01
4
+ version: 0.3.02
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-12-17 00:00:00.000000000 Z
11
+ date: 2020-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler