mini_kraken 0.1.06 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -1
  3. data/CHANGELOG.md +56 -1
  4. data/README.md +11 -3
  5. data/lib/mini_kraken/core/association_walker.rb +1 -1
  6. data/lib/mini_kraken/core/base_arg.rb +10 -0
  7. data/lib/mini_kraken/core/conj2.rb +58 -65
  8. data/lib/mini_kraken/core/cons_cell.rb +49 -43
  9. data/lib/mini_kraken/core/def_relation.rb +49 -0
  10. data/lib/mini_kraken/core/disj2.rb +72 -0
  11. data/lib/mini_kraken/core/duck_fiber.rb +1 -1
  12. data/lib/mini_kraken/core/environment.rb +1 -1
  13. data/lib/mini_kraken/core/equals.rb +134 -126
  14. data/lib/mini_kraken/core/fail.rb +18 -14
  15. data/lib/mini_kraken/core/formal_arg.rb +22 -0
  16. data/lib/mini_kraken/core/formal_ref.rb +24 -0
  17. data/lib/mini_kraken/core/goal_arg.rb +5 -3
  18. data/lib/mini_kraken/core/goal_relation.rb +13 -0
  19. data/lib/mini_kraken/core/goal_template.rb +60 -0
  20. data/lib/mini_kraken/core/k_boolean.rb +31 -0
  21. data/lib/mini_kraken/core/outcome.rb +40 -24
  22. data/lib/mini_kraken/core/succeed.rb +17 -13
  23. data/lib/mini_kraken/core/vocabulary.rb +37 -17
  24. data/lib/mini_kraken/glue/fresh_env.rb +45 -3
  25. data/lib/mini_kraken/glue/run_star_expression.rb +45 -19
  26. data/lib/mini_kraken/version.rb +1 -1
  27. data/spec/core/conj2_spec.rb +8 -9
  28. data/spec/core/cons_cell_spec.rb +8 -0
  29. data/spec/core/def_relation_spec.rb +96 -0
  30. data/spec/core/disj2_spec.rb +99 -0
  31. data/spec/core/duck_fiber_spec.rb +12 -1
  32. data/spec/core/equals_spec.rb +3 -3
  33. data/spec/core/goal_template_spec.rb +74 -0
  34. data/spec/core/k_boolean_spec.rb +107 -0
  35. data/spec/core/outcome_spec.rb +48 -0
  36. data/spec/core/vocabulary_spec.rb +11 -5
  37. data/spec/glue/fresh_env_spec.rb +27 -1
  38. data/spec/glue/run_star_expression_spec.rb +538 -70
  39. data/spec/mini_kraken_spec.rb +2 -0
  40. data/spec/spec_helper.rb +0 -1
  41. data/spec/support/factory_methods.rb +17 -1
  42. metadata +19 -2
@@ -66,15 +66,14 @@ module MiniKraken
66
66
  end
67
67
 
68
68
  it 'should yield success and set associations' do
69
- # # Weird: this example succeeds if run alone...
70
- # # Covers frame 1-51
71
- # env.add_var(var_q)
72
- # sub_goal = Goal.new(Equals.instance, [corn, ref_q])
73
- # solver = subject.solver_for([succeeds, sub_goal], env)
74
- # outcome = solver.resume
75
- # expect(outcome).to be_successful
76
- # expect(outcome.associations).not_to be_empty
77
- # expect(outcome.associations['q'].first.value).to eq(corn)
69
+ # Covers frame 1-51
70
+ env.add_var(var_q)
71
+ sub_goal = Goal.new(Equals.instance, [corn, ref_q])
72
+ solver = subject.solver_for([succeeds, sub_goal], env)
73
+ outcome = solver.resume
74
+ expect(outcome).to be_successful
75
+ expect(outcome.associations).not_to be_empty
76
+ expect(outcome.associations['q'].first.value).to eq(corn)
78
77
  end
79
78
 
80
79
  it 'should yield fails and set no associations' do
@@ -58,6 +58,14 @@ module MiniKraken
58
58
  different = ConsCell.new(pea)
59
59
  expect(subject.eql?(different)).to be_falsey
60
60
  end
61
+
62
+ it 'should append another cons cell' do
63
+ instance = ConsCell.new(pea)
64
+ trail = ConsCell.new(pod)
65
+ instance.append(trail)
66
+ expect(instance.car).to eq(pea)
67
+ expect(instance.cdr).to eq(trail)
68
+ end
61
69
  end # context
62
70
  end # describe
63
71
  end # module
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/disj2'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/formal_arg'
7
+ require_relative '../../lib/mini_kraken/core/formal_ref'
8
+ require_relative '../../lib/mini_kraken/core/goal'
9
+ require_relative '../../lib/mini_kraken/core/goal_template'
10
+ require_relative '../../lib/mini_kraken/core/k_symbol'
11
+ require_relative '../../lib/mini_kraken/core/variable_ref'
12
+ require_relative '../../lib/mini_kraken/core/environment'
13
+
14
+ # Load the class under test
15
+ require_relative '../../lib/mini_kraken/core/def_relation'
16
+
17
+ module MiniKraken
18
+ module Core
19
+ describe DefRelation do
20
+ let(:tea) { KSymbol.new(:tea) }
21
+ let(:formal_t) { FormalArg.new('t') }
22
+ let(:t_ref) { FormalRef.new('t') }
23
+ let(:equals_tea) { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
24
+ subject { DefRelation.new('teao', equals_tea, [formal_t]) }
25
+
26
+ context 'Initialization:' do
27
+ it 'should be initialized with a name, a goal template, formal args' do
28
+ expect { DefRelation.new('teao', equals_tea, [formal_t]) }.not_to raise_error
29
+ end
30
+
31
+ it 'should know its name' do
32
+ expect(subject.name).to eq('teao')
33
+ end
34
+
35
+ it 'should know its goal template' do
36
+ expect(subject.goal_template).to eq(equals_tea)
37
+ end
38
+
39
+ it 'should know its formals' do
40
+ expect(subject.formals).to eq([formal_t])
41
+ end
42
+ end # context
43
+
44
+ context 'Provided services:' do
45
+ let(:cup) { KSymbol.new(:cup) }
46
+ let(:ref_x) { VariableRef.new('x') }
47
+ let(:equals_cup) { GoalTemplate.new(Equals.instance, [cup, t_ref]) }
48
+ let(:g_template) { GoalTemplate.new(Disj2.instance, [equals_tea, equals_cup]) }
49
+ subject { DefRelation.new('teacup', g_template, [formal_t]) }
50
+ let(:env) { Environment.new }
51
+
52
+ it 'should provide solver for a single-node goal without var ref' do
53
+ defrel = DefRelation.new('teao', equals_tea, [formal_t])
54
+ solver = defrel.solver_for([tea], env)
55
+ outcome = solver.resume
56
+ expect(outcome).to be_successful
57
+ outcome = solver.resume
58
+ expect(outcome).to be_nil
59
+
60
+ solver = defrel.solver_for([cup], env)
61
+ outcome = solver.resume
62
+ expect(outcome).not_to be_successful
63
+ outcome = solver.resume
64
+ expect(outcome).to be_nil
65
+ end
66
+
67
+ it 'should provide solver for a single-node goal' do
68
+ defrel = DefRelation.new('teao', equals_tea, [formal_t])
69
+ env.add_var(Variable.new('x'))
70
+ solver = defrel.solver_for([ref_x], env)
71
+ outcome = solver.resume
72
+ expect(outcome).to be_successful
73
+ expect(ref_x.value(outcome)).to eq(tea)
74
+
75
+ outcome = solver.resume
76
+ expect(outcome).to be_nil
77
+ end
78
+
79
+ it 'should provide solver for a single-node goal' do
80
+ env.add_var(Variable.new('x'))
81
+ solver = subject.solver_for([ref_x], env)
82
+ outcome = solver.resume
83
+ expect(outcome).to be_successful
84
+ expect(ref_x.value(outcome)).to eq(tea)
85
+
86
+ outcome = solver.resume
87
+ expect(outcome).to be_successful
88
+ expect(ref_x.value(outcome)).to eq(cup)
89
+
90
+ outcome = solver.resume
91
+ expect(outcome).to be_nil
92
+ end
93
+ end # context
94
+ end # describe
95
+ end # module
96
+ end # module
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/k_symbol'
5
+ require_relative '../../lib/mini_kraken/core/fail'
6
+ require_relative '../../lib/mini_kraken/core/succeed'
7
+ require_relative '../../lib/mini_kraken/core/equals'
8
+ require_relative '../../lib/mini_kraken/core/environment'
9
+ require_relative '../../lib/mini_kraken/core/variable'
10
+ require_relative '../../lib/mini_kraken/core/variable_ref'
11
+
12
+ # Load the class under test
13
+ require_relative '../../lib/mini_kraken/core/disj2'
14
+
15
+ module MiniKraken
16
+ module Core
17
+ describe Disj2 do
18
+ subject { Disj2.instance }
19
+
20
+ context 'Initialization:' do
21
+ it 'should be initialized without argument' do
22
+ expect { Disj2.instance }.not_to raise_error
23
+ end
24
+
25
+ it 'should know its name' do
26
+ expect(subject.name).to eq('disj2')
27
+ end
28
+ end # context
29
+
30
+ context 'Provided services:' do
31
+ let(:corn) { KSymbol.new(:corn) }
32
+ let(:meal) { KSymbol.new(:meal) }
33
+ let(:oil) { KSymbol.new(:oil) }
34
+ let(:olive) { KSymbol.new(:olive) }
35
+ let(:pea) { KSymbol.new(:pea) }
36
+ let(:fails) { Goal.new(Fail.instance, []) }
37
+ let(:succeeds) { Goal.new(Succeed.instance, []) }
38
+ let(:var_q) { Variable.new('q') }
39
+ let(:ref_q) { VariableRef.new('q') }
40
+ let(:env) do
41
+ e = Environment.new
42
+ e.add_var(var_q)
43
+ e
44
+ end
45
+
46
+ it 'should complain when one of its argument is not a goal' do
47
+ err = StandardError
48
+ expect { subject.solver_for([succeeds, pea], env) }.to raise_error(err)
49
+ expect { subject.solver_for([pea, succeeds], env) }.to raise_error(err)
50
+ end
51
+
52
+ it 'should fails if both arguments fail' do
53
+ # Covers frame 1:55
54
+ solver = subject.solver_for([fails, fails], env)
55
+ expect(solver.resume).not_to be_successful
56
+ expect(solver.resume).to be_nil
57
+ end
58
+
59
+ it 'yield success if first argument succeeds' do
60
+ # Covers frame 1:56
61
+ subgoal = Goal.new(Equals.instance, [olive, ref_q])
62
+ solver = subject.solver_for([subgoal, fails], env)
63
+ outcome = solver.resume
64
+ expect(outcome).to be_successful
65
+ expect(outcome.associations['q'].first.value).to eq(olive)
66
+ expect(solver.resume).to be_nil
67
+ end
68
+
69
+ it 'yield success if second argument succeeds' do
70
+ # Covers frame 1:57
71
+ subgoal = Goal.new(Equals.instance, [oil, ref_q])
72
+ solver = subject.solver_for([fails, subgoal], env)
73
+ outcome = solver.resume
74
+ expect(outcome).to be_successful
75
+ expect(outcome.associations['q'].first.value).to eq(oil)
76
+ expect(solver.resume).to be_nil
77
+ end
78
+
79
+ it 'yield two solutions if both arguments succeed' do
80
+ # Covers frame 1:58
81
+ subgoal1 = Goal.new(Equals.instance, [olive, ref_q])
82
+ subgoal2 = Goal.new(Equals.instance, [oil, ref_q])
83
+ solver = subject.solver_for([subgoal1, subgoal2], env)
84
+
85
+ # First solution
86
+ outcome1 = solver.resume
87
+ expect(outcome1).to be_successful
88
+ expect(outcome1.associations['q'].first.value).to eq(olive)
89
+
90
+ # Second solution
91
+ outcome2 = solver.resume
92
+ expect(outcome2).to be_successful
93
+ expect(outcome2.associations['q'].first.value).to eq(oil)
94
+ expect(solver.resume).to be_nil
95
+ end
96
+ end # context
97
+ end # describe
98
+ end # module
99
+ end # module
@@ -40,12 +40,23 @@ module MiniKraken
40
40
  succeeding = DuckFiber.new(:success)
41
41
  outcome = nil
42
42
  expect { outcome = succeeding.resume }.not_to raise_error
43
- expect(outcome).to eq(BasicSuccess)
43
+ expect(outcome).to be_successful
44
+ expect(outcome.parent).to be_nil
44
45
 
45
46
  # Only one result should be yielded
46
47
  expect(succeeding.resume).to be_nil
47
48
  end
48
49
 
50
+ it 'should yield a distinct success object' do
51
+ instance1 = DuckFiber.new(:success)
52
+ outcome1 = instance1.resume
53
+
54
+ instance2 = DuckFiber.new(:success)
55
+ outcome2 = instance1.resume
56
+
57
+ expect(outcome1).not_to be_equal(outcome2)
58
+ end
59
+
49
60
  it 'should behave like a Fiber yielding a custom outcome' do
50
61
  tailored = DuckFiber.new(:custom) { Outcome.new(:"#s", parent) }
51
62
  outcome = nil
@@ -275,9 +275,9 @@ module MiniKraken
275
275
 
276
276
  it 'should unify composite terms with variables' do
277
277
  # Reasoned S2, frame 1:36
278
- # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
279
- expr1 = cons(cons(ref_q), ref_x)
280
- expr2 = cons(cons(ref_x), pod)
278
+ # (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
279
+ expr1 = cons(cons(cons(ref_q)), ref_x)
280
+ expr2 = cons(cons(cons(ref_x)), pod)
281
281
 
282
282
  result = solve_for(expr1, expr2)
283
283
  # require 'debug'
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/disj2'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/formal_arg'
7
+ require_relative '../../lib/mini_kraken/core/formal_ref'
8
+ require_relative '../../lib/mini_kraken/core/goal'
9
+ require_relative '../../lib/mini_kraken/core/k_symbol'
10
+ require_relative '../../lib/mini_kraken/core/variable_ref'
11
+ # require_relative '../../lib/mini_kraken/core/environment'
12
+
13
+ # Load the class under test
14
+ require_relative '../../lib/mini_kraken/core/goal_template'
15
+
16
+
17
+ module MiniKraken
18
+ module Core
19
+ describe GoalTemplate do
20
+ let(:tea) { KSymbol.new(:tea) }
21
+ let(:t_ref) { FormalRef.new('t') }
22
+ subject { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
23
+
24
+ context 'Initialization:' do
25
+ it 'should be initialized with a relation and args' do
26
+ expect { GoalTemplate.new(Equals.instance, [tea, t_ref]) }.not_to raise_error
27
+ end
28
+
29
+ it 'should know its relation' do
30
+ expect(subject.relation).to eq(Equals.instance)
31
+ end
32
+
33
+ it 'should know its arguments' do
34
+ expect(subject.args[0]).to eq(tea)
35
+ expect(subject.args[1]).to eq(t_ref)
36
+ end
37
+ end # context
38
+
39
+ context 'Provided services:' do
40
+ let(:formal_t) { FormalArg.new('t') }
41
+ let(:cup) { KSymbol.new(:cup) }
42
+ let(:ref_x) { VariableRef.new('x') }
43
+ # let(:env) { Environment.new }
44
+
45
+ it 'should instantiate a single-node goal' do
46
+ expect(subject.instantiate([formal_t], [cup])).to be_kind_of(Goal)
47
+ goal = subject.instantiate([formal_t], [cup])
48
+ expect(goal.relation).to eq(Equals.instance)
49
+ expect(goal.actuals[0]).to eq(tea)
50
+ expect(goal.actuals[1]).to eq(cup)
51
+ end
52
+
53
+ it 'should instantiate a multiple-nodes goal' do
54
+ sub_tmp1 = GoalTemplate.new(Equals.instance, [tea, t_ref])
55
+ sub_tmp2 = GoalTemplate.new(Equals.instance, [cup, t_ref])
56
+ template = GoalTemplate.new(Disj2.instance, [sub_tmp1, sub_tmp2])
57
+
58
+ goal = template.instantiate([formal_t], [ref_x])
59
+ expect(goal.relation).to eq(Disj2.instance)
60
+ subgoal1 = goal.actuals[0]
61
+ expect(subgoal1).to be_kind_of(Goal)
62
+ expect(subgoal1.relation).to eq(Equals.instance)
63
+ expect(subgoal1.actuals[0]).to eq(tea)
64
+ expect(subgoal1.actuals[1]).to eq(ref_x)
65
+ subgoal2 = goal.actuals[1]
66
+ expect(subgoal2).to be_kind_of(Goal)
67
+ expect(subgoal2.relation).to eq(Equals.instance)
68
+ expect(subgoal2.actuals[0]).to eq(cup)
69
+ expect(subgoal2.actuals[1]).to eq(ref_x)
70
+ end
71
+ end # context
72
+ end # describe
73
+ end # module
74
+ end # module
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require 'ostruct'
5
+
6
+ # Load the class under test
7
+ require_relative '../../lib/mini_kraken/core/k_boolean'
8
+
9
+ module MiniKraken
10
+ module Core
11
+ describe KBoolean do
12
+ subject { KBoolean.new('#t') }
13
+
14
+ context 'Initialization:' do
15
+ it 'could be created with a Ruby true/false value' do
16
+ expect { KBoolean.new(true) }.not_to raise_error
17
+ expect { KBoolean.new(false) }.not_to raise_error
18
+ end
19
+
20
+ it 'could be created with a Ruby Symbol value' do
21
+ expect { KBoolean.new(:"#t") }.not_to raise_error
22
+ expect { KBoolean.new(:"#f") }.not_to raise_error
23
+ end
24
+
25
+ it 'could be created with a Ruby String value' do
26
+ expect { KBoolean.new('#t') }.not_to raise_error
27
+ expect { KBoolean.new('#f') }.not_to raise_error
28
+ end
29
+
30
+ it 'should know its value' do
31
+ expect(subject.value).to eq(true)
32
+ end
33
+
34
+ it 'should know that it is a ground term' do
35
+ env = double('mock-env')
36
+ expect(subject.ground?(env)).to be_truthy
37
+ end
38
+ end # context
39
+
40
+ context 'Provided services:' do
41
+ it 'should know whether it is equal to another instance' do
42
+ # Same type, same value
43
+ other = KBoolean.new(true)
44
+ expect(subject).to be_eql(other)
45
+
46
+ other = KBoolean.new(:"#t")
47
+ expect(subject).to be_eql(other)
48
+
49
+ other = KBoolean.new('#t')
50
+ expect(subject).to be_eql(other)
51
+
52
+ # Same type, other value
53
+ another = KBoolean.new(false)
54
+ expect(subject).not_to be_eql(another)
55
+
56
+ # Same type, other value
57
+ another = KBoolean.new(:"#f")
58
+ expect(subject).not_to be_eql(another)
59
+
60
+ # Same type, other value
61
+ another = KBoolean.new('#f')
62
+ expect(subject).not_to be_eql(another)
63
+
64
+ # Different type, same value
65
+ yet_another = OpenStruct.new(value: true)
66
+ expect(subject).not_to be_eql(yet_another)
67
+ end
68
+
69
+ it 'should know whether it has same value than other object' do
70
+ # Same type, same value
71
+ other = KBoolean.new(true)
72
+ expect(subject == other).to be_truthy
73
+
74
+ other = KBoolean.new(:"#t")
75
+ expect(subject == other).to be_truthy
76
+
77
+ other = KBoolean.new('#t')
78
+ expect(subject == other).to be_truthy
79
+
80
+ # Same type, other value
81
+ another = KBoolean.new(false)
82
+ expect(subject == another).to be_falsy
83
+
84
+ another = KBoolean.new(:"#f")
85
+ expect(subject == another).to be_falsy
86
+
87
+ another = KBoolean.new('#f')
88
+ expect(subject == another).to be_falsy
89
+
90
+ # Same duck type, same value
91
+ yet_another = OpenStruct.new(value: true)
92
+ expect(subject == yet_another).to be_truthy
93
+
94
+ # Different duck type, different value
95
+ still_another = OpenStruct.new(value: false)
96
+ expect(subject == still_another).to be_falsy
97
+
98
+ # Default Ruby representation, same value
99
+ expect(subject == true).to be_truthy
100
+
101
+ # Default Ruby representation, different value
102
+ expect(subject == false).to be_falsy
103
+ end
104
+ end # context
105
+ end # describe
106
+ end # module
107
+ end # module