mini_kraken 0.1.13 → 0.2.00
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +85 -5
- data/lib/mini_kraken.rb +8 -1
- data/lib/mini_kraken/core/any_value.rb +5 -1
- data/lib/mini_kraken/core/cons_cell.rb +28 -1
- data/lib/mini_kraken/core/goal.rb +3 -2
- data/lib/mini_kraken/core/k_symbol.rb +11 -0
- data/lib/mini_kraken/glue/dsl.rb +104 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/cons_cell_spec.rb +35 -0
- data/spec/core/k_symbol_spec.rb +4 -0
- data/spec/glue/dsl_chap1_spec.rb +498 -0
- data/spec/glue/run_star_expression_spec.rb +6 -7
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bbfe3d58d4c7271a5c8a54486a743c51d6fddcb3b068095cad44cacad575c83
|
4
|
+
data.tar.gz: 012b412a95752592b5be70859e00d94b379e2c4c564d37d932a300a03cbc9716
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 952d93b01de392c7168e7cfb4a3cc911e4d1b53be11a4a10d67012bb4ab4a8f69aa42f41bf13a756f89a6d09eb775a5594174d73334c57c2230039b7991e89fd
|
7
|
+
data.tar.gz: a60adbd5da627495badab63de355336f131a5e599c40226931366a7c1b4a349b2542ccb55cf30ef8e60990341c1f5d8547804b1552fbbbc504bd1bed40a36d9e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## [0.2.00] - 2020-07-12
|
2
|
+
- First release of DSL (Domain Specific Language)
|
3
|
+
- Fix defect for fused variables that remain fresh
|
4
|
+
|
5
|
+
### NEW
|
6
|
+
- Mix-in module `Glue::DSL` hosting methods for implementing the DSL.
|
7
|
+
- Method `ConsCell#to_s` uses the Lisp convention for representing lists.
|
8
|
+
|
9
|
+
### CHANGED
|
10
|
+
- File `README.md` Added a couple of examples of DSL use.
|
11
|
+
- Method `AnyValue#==` can compare with symbols with format '_' + integer literal (e.g. :_0).
|
12
|
+
|
1
13
|
## [0.1.13] - 2020-07-01
|
2
14
|
- Cover all frames from Chapter One of "Reasoned Scheme" book.
|
3
15
|
- Fix defect for fused variables that remain fresh
|
data/README.md
CHANGED
@@ -4,22 +4,29 @@
|
|
4
4
|
[](https://github.com/famished-tiger/mini_kraken/blob/master/LICENSE.txt)
|
5
5
|
|
6
6
|
### What is __mini_kraken__ ?
|
7
|
-
|
7
|
+
A library containing an implementation of the [miniKanren](http://minikanren.org/)
|
8
|
+
relational programming language in Ruby.
|
8
9
|
*miniKanren* is a small language for relational (logic) programming.
|
9
10
|
Based on the reference implementation, in Scheme from the "The Reasoned Schemer" book.
|
10
11
|
Daniel P. Friedman, William E. Byrd, Oleg Kiselyov, and Jason Hemann: "The Reasoned Schemer", Second Edition,
|
11
12
|
ISBN: 9780262535519, (2018), MIT Press.
|
12
13
|
|
13
14
|
### Features
|
15
|
+
- Pure Ruby implementation, not a port from another language
|
16
|
+
- Object-Oriented design
|
17
|
+
- No runtime dependencies
|
18
|
+
|
19
|
+
### miniKanren Features
|
14
20
|
- [X] ==
|
15
21
|
- [X] run\*
|
16
|
-
- [X] fresh
|
22
|
+
- [X] fresh
|
23
|
+
- [X] conde
|
17
24
|
- [X] conj2
|
18
25
|
- [X] disj2
|
19
26
|
- [X] defrel
|
20
27
|
|
21
28
|
### TODO
|
22
|
-
|
29
|
+
|
23
30
|
- [ ] Occurs check
|
24
31
|
|
25
32
|
List-centric relations from Chapter 2
|
@@ -46,9 +53,82 @@ Or install it yourself as:
|
|
46
53
|
|
47
54
|
$ gem install mini_kraken
|
48
55
|
|
49
|
-
##
|
56
|
+
## Examples
|
57
|
+
|
58
|
+
The following __MiniKraken__ examples use its DSL (Domain Specific Language).
|
59
|
+
|
60
|
+
### Example 1
|
61
|
+
Let's first begin with a rather simplistic example.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
require 'mini_kraken' # Load MiniKraken library
|
65
|
+
|
66
|
+
extend(MiniKraken::Glue::DSL) # Add DSL method to self (object in context)
|
67
|
+
|
68
|
+
result = run_star('q', equals(q, :pea))
|
69
|
+
puts result # => (:pea)
|
70
|
+
```
|
71
|
+
|
72
|
+
The two first lines in the above code snippet are pretty standard:
|
73
|
+
- The first line loads the `mini_kraken` library.
|
74
|
+
- The second line add the DSL methods to the current object.
|
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.
|
79
|
+
In our example, the `run_star` method instructs `MiniKraken` to find all solutions,
|
80
|
+
knowing that each successful solution:
|
81
|
+
- binds a value to the provided variable `q` and
|
82
|
+
- meets the goal `equals(q, :pea)`.
|
83
|
+
|
84
|
+
The goal `equals(q, :pea)` succeeds because the logical variable `q` is _fresh_ (that is,
|
85
|
+
not yet bound to a value) and will be bound to the symbol `:pea` as a side effect
|
86
|
+
of the goal `equals`.
|
87
|
+
|
88
|
+
So the above program succeeds and the only found solution is obtained by binding
|
89
|
+
the variable `q` to the value :pea. Hence the result of the `puts` method.
|
90
|
+
|
91
|
+
### Example 2
|
92
|
+
The next example illustrates the behavior of a failing `miniKanren` program.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
require 'mini_kraken' # Load MiniKraken library
|
96
|
+
|
97
|
+
extend(MiniKraken::Glue::DSL) # Add DSL method to self (object in context)
|
98
|
+
|
99
|
+
# Following miniKanren program fails
|
100
|
+
result = run_star('q', [equals(q, :pea), equals(q, :pod)])
|
101
|
+
puts result # => ()
|
102
|
+
```
|
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.
|
105
|
+
|
106
|
+
|
107
|
+
### Example 3
|
108
|
+
The next example shows the use two logical variables.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
# In this example and following, one assumes that DSL is loaded as shown in Example 1
|
112
|
+
|
113
|
+
result = run_star(['x', 'y'], [equals(:hello, x), equals(y, :world)])
|
114
|
+
puts result # => ((:hello :world))
|
115
|
+
```
|
50
116
|
|
51
|
-
|
117
|
+
This time, `run_star` takes two logical variables -`x` and `y`- and successfully finds the solution `x = :hello, y = :world`.
|
118
|
+
|
119
|
+
### Example 4
|
120
|
+
The next example shows the use of `disj2` goals.
|
121
|
+
```ruby
|
122
|
+
result = run_star(['x', 'y'],
|
123
|
+
[
|
124
|
+
disj2(equals(x, :blue), equals(x, :red)),
|
125
|
+
disj2(equals(y, :sea), equals(:mountain, y))
|
126
|
+
])
|
127
|
+
puts result # => ((:blue :sea) (:blue :mountain) (:red :sea) (:red :mountain))
|
128
|
+
```
|
129
|
+
|
130
|
+
Here, `run_star` takes two logical variables and two `disj2` goals. A `disj2` succeeds if any of its arguments succeeds.
|
131
|
+
This program finds four distinct solutions for x, y pairs.
|
52
132
|
|
53
133
|
## Development
|
54
134
|
|
data/lib/mini_kraken.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# This file acts as a jumping-off point for loading dependencies expected
|
4
|
+
# for a MiniKraken client.
|
5
|
+
|
6
|
+
require_relative './mini_kraken/version'
|
7
|
+
require_relative './mini_kraken/glue/dsl'
|
8
|
+
|
9
|
+
|
10
|
+
# End of file
|
4
11
|
|
5
12
|
module MiniKraken
|
6
13
|
class Error < StandardError; end
|
@@ -12,7 +12,11 @@ module MiniKraken
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def ==(other)
|
15
|
-
|
15
|
+
if other.is_a?(AnyValue)
|
16
|
+
rank == other.rank
|
17
|
+
elsif other.id2name =~ /_\d+/
|
18
|
+
rank == other.id2name.sub(/_/, '').to_i
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
# Use same text representation as in Reasoned Schemer.
|
@@ -11,7 +11,11 @@ unless MiniKraken::Core.constants(false).include? :ConsCell
|
|
11
11
|
|
12
12
|
def initialize(obj1, obj2 = nil)
|
13
13
|
@car = obj1
|
14
|
-
|
14
|
+
if obj2.kind_of?(ConsCell) && obj2.null?
|
15
|
+
@cdr = nil
|
16
|
+
else
|
17
|
+
@cdr = obj2
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
def children
|
@@ -42,9 +46,32 @@ unless MiniKraken::Core.constants(false).include? :ConsCell
|
|
42
46
|
ConsCell.new(new_car, new_cdr)
|
43
47
|
end
|
44
48
|
|
49
|
+
# Use the list notation from Lisp as a text representation.
|
50
|
+
def to_s
|
51
|
+
return '()' if null?
|
52
|
+
|
53
|
+
"(#{pair_to_s})"
|
54
|
+
end
|
55
|
+
|
45
56
|
def append(another)
|
46
57
|
@cdr = another
|
47
58
|
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def pair_to_s
|
63
|
+
result = +car.to_s
|
64
|
+
if cdr
|
65
|
+
result << ' '
|
66
|
+
if cdr.kind_of?(ConsCell)
|
67
|
+
result << cdr.pair_to_s
|
68
|
+
else
|
69
|
+
result << ". #{cdr}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
result
|
74
|
+
end
|
48
75
|
end # class
|
49
76
|
|
50
77
|
# Constant representing the null (empty) list.
|
@@ -35,14 +35,15 @@ module MiniKraken
|
|
35
35
|
raise StandardError, err_msg
|
36
36
|
end
|
37
37
|
|
38
|
-
prefix =
|
38
|
+
prefix = "Invalid goal argument '"
|
39
39
|
args.each do |actual|
|
40
40
|
if actual.kind_of?(GoalArg) || actual.kind_of?(Environment)
|
41
41
|
next
|
42
42
|
elsif actual.kind_of?(Array)
|
43
43
|
validated_actuals(actual)
|
44
44
|
else
|
45
|
-
|
45
|
+
actual_display = actual.nil? ? 'nil' : actual.to_s
|
46
|
+
raise StandardError, prefix + actual_display + "'"
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -11,6 +11,17 @@ module MiniKraken
|
|
11
11
|
def initialize(aValue)
|
12
12
|
super(aValue)
|
13
13
|
end
|
14
|
+
|
15
|
+
# Returns the name or string corresponding to value.
|
16
|
+
# @return [String]
|
17
|
+
def id2name
|
18
|
+
value.id2name
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a string representing the MiniKraken symbol.
|
22
|
+
def to_s
|
23
|
+
':' + id2name
|
24
|
+
end
|
14
25
|
end # class
|
15
26
|
end # module
|
16
27
|
end # module
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../core/any_value'
|
4
|
+
require_relative '../core/conj2'
|
5
|
+
require_relative '../core/cons_cell'
|
6
|
+
require_relative '../core/disj2'
|
7
|
+
require_relative '../core/equals'
|
8
|
+
require_relative '../core/fail'
|
9
|
+
require_relative '../core/k_symbol'
|
10
|
+
require_relative '../core/succeed'
|
11
|
+
require_relative '../core/variable_ref'
|
12
|
+
require_relative 'fresh_env'
|
13
|
+
require_relative 'run_star_expression'
|
14
|
+
|
15
|
+
|
16
|
+
module MiniKraken
|
17
|
+
module Glue
|
18
|
+
module DSL
|
19
|
+
# @return [Core::ConsCell] A list of solutions
|
20
|
+
def run_star(var_names, goal)
|
21
|
+
program = RunStarExpression.new(var_names, goal)
|
22
|
+
program.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def conj2(arg1, arg2)
|
26
|
+
Core::Goal.new(Core::Conj2.instance, [convert(arg1), convert(arg2)])
|
27
|
+
end
|
28
|
+
|
29
|
+
def cons(car_item, cdr_item = nil)
|
30
|
+
Core::ConsCell.new(convert(car_item), convert(cdr_item))
|
31
|
+
end
|
32
|
+
|
33
|
+
def disj2(arg1, arg2)
|
34
|
+
Core::Goal.new(Core::Disj2.instance, [convert(arg1), convert(arg2)])
|
35
|
+
end
|
36
|
+
|
37
|
+
def _fail
|
38
|
+
Core::Goal.new(Core::Fail.instance, [])
|
39
|
+
end
|
40
|
+
|
41
|
+
def equals(arg1, arg2)
|
42
|
+
Core::Goal.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
|
43
|
+
end
|
44
|
+
|
45
|
+
def fresh(var_names, goal)
|
46
|
+
vars = nil
|
47
|
+
|
48
|
+
if var_names.kind_of?(String) || var_names.kind_of?(Core::VariableRef)
|
49
|
+
vars = [var_names]
|
50
|
+
elsif
|
51
|
+
|
52
|
+
vars = var_names
|
53
|
+
end
|
54
|
+
FreshEnv.new(vars, goal)
|
55
|
+
end
|
56
|
+
|
57
|
+
def null
|
58
|
+
Core::ConsCell.new(nil, nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
def succeed
|
62
|
+
Core::Goal.new(Core::Succeed.instance, [])
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def convert(anArgument)
|
68
|
+
converted = nil
|
69
|
+
|
70
|
+
case anArgument
|
71
|
+
when Symbol
|
72
|
+
if anArgument.id2name =~ /_\d+/
|
73
|
+
rank = anArgument.id2name.slice(1..-1).to_i
|
74
|
+
any_val = Core::AnyValue.allocate
|
75
|
+
any_val.instance_variable_set(:@rank, rank)
|
76
|
+
converted = any_val
|
77
|
+
else
|
78
|
+
converted = Core::KSymbol.new(anArgument)
|
79
|
+
end
|
80
|
+
when Core::Goal
|
81
|
+
converted = anArgument
|
82
|
+
when Core::VariableRef
|
83
|
+
converted = anArgument
|
84
|
+
when Core::ConsCell
|
85
|
+
converted = anArgument
|
86
|
+
end
|
87
|
+
|
88
|
+
converted
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(mth, *args)
|
92
|
+
result = nil
|
93
|
+
|
94
|
+
begin
|
95
|
+
result = super(mth, *args)
|
96
|
+
rescue NameError
|
97
|
+
result = Core::VariableRef.new(mth.id2name)
|
98
|
+
end
|
99
|
+
|
100
|
+
result
|
101
|
+
end
|
102
|
+
end # module
|
103
|
+
end # module
|
104
|
+
end # module
|
data/lib/mini_kraken/version.rb
CHANGED
data/spec/core/cons_cell_spec.rb
CHANGED
@@ -11,6 +11,7 @@ module MiniKraken
|
|
11
11
|
describe ConsCell do
|
12
12
|
let(:pea) { KSymbol.new(:pea) }
|
13
13
|
let(:pod) { KSymbol.new(:pod) }
|
14
|
+
let(:corn) { KSymbol.new(:corn) }
|
14
15
|
subject { ConsCell.new(pea, pod) }
|
15
16
|
|
16
17
|
context 'Initialization:' do
|
@@ -39,6 +40,12 @@ module MiniKraken
|
|
39
40
|
expect(ConsCell.new(nil, nil)).to be_null
|
40
41
|
expect(NullList).to be_null
|
41
42
|
end
|
43
|
+
|
44
|
+
it 'simplifies cdr if its referencing a null list' do
|
45
|
+
instance = ConsCell.new(pea, NullList)
|
46
|
+
expect(instance.car).to eq(pea)
|
47
|
+
expect(instance.cdr).to be_nil
|
48
|
+
end
|
42
49
|
end # context
|
43
50
|
|
44
51
|
context 'Provided services:' do
|
@@ -66,6 +73,34 @@ module MiniKraken
|
|
66
73
|
expect(instance.car).to eq(pea)
|
67
74
|
expect(instance.cdr).to eq(trail)
|
68
75
|
end
|
76
|
+
|
77
|
+
it 'should provide a list representation of itself' do
|
78
|
+
# Case of null list
|
79
|
+
expect(NullList.to_s).to eq '()'
|
80
|
+
|
81
|
+
# Case of one element proper list
|
82
|
+
cell = ConsCell.new(pea)
|
83
|
+
expect(cell.to_s).to eq '(:pea)'
|
84
|
+
|
85
|
+
# Case of two elements proper list
|
86
|
+
cell = ConsCell.new(pea, ConsCell.new(pod))
|
87
|
+
expect(cell.to_s).to eq '(:pea :pod)'
|
88
|
+
|
89
|
+
# Case of two elements improper list
|
90
|
+
expect(subject.to_s).to eq '(:pea . :pod)'
|
91
|
+
|
92
|
+
# Case of three elements proper list
|
93
|
+
cell = ConsCell.new(pea, ConsCell.new(pod, ConsCell.new(corn)))
|
94
|
+
expect(cell.to_s).to eq '(:pea :pod :corn)'
|
95
|
+
|
96
|
+
# Case of three elements improper list
|
97
|
+
cell = ConsCell.new(pea, ConsCell.new(pod, corn))
|
98
|
+
expect(cell.to_s).to eq '(:pea :pod . :corn)'
|
99
|
+
|
100
|
+
# Case of a nested list
|
101
|
+
cell = ConsCell.new(ConsCell.new(pea), ConsCell.new(pod))
|
102
|
+
expect(cell.to_s).to eq '((:pea) :pod)'
|
103
|
+
end
|
69
104
|
end # context
|
70
105
|
end # describe
|
71
106
|
end # module
|
data/spec/core/k_symbol_spec.rb
CHANGED
@@ -65,6 +65,10 @@ module MiniKraken
|
|
65
65
|
# Default Ruby representation, different value
|
66
66
|
expect(subject == :pod).to be_falsy
|
67
67
|
end
|
68
|
+
|
69
|
+
it 'should provide a string representation of itself' do
|
70
|
+
expect(subject.to_s).to eq(':pea')
|
71
|
+
end
|
68
72
|
end # context
|
69
73
|
end # describe
|
70
74
|
end # module
|
@@ -0,0 +1,498 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/mini_kraken/glue/dsl'
|
7
|
+
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Glue
|
11
|
+
describe 'DSL (Chap 1)' do
|
12
|
+
include DSL
|
13
|
+
|
14
|
+
context 'Chapter 1 examples:' do
|
15
|
+
it 'passes frame 1:7' do
|
16
|
+
# Reasoned S2, frame 1:7
|
17
|
+
# (run* q #u) ;; => ()
|
18
|
+
|
19
|
+
result = run_star('q', _fail)
|
20
|
+
expect(result).to be_null
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'passes frame 1:10' do
|
24
|
+
# Reasoned S2, frame 1:10
|
25
|
+
# (run* q (== 'pea 'pod) ;; => ()
|
26
|
+
|
27
|
+
result = run_star('q', equals(:pea, :pod))
|
28
|
+
expect(result).to be_null
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'passes frame 1:11' do
|
32
|
+
# Reasoned S2, frame 1:11
|
33
|
+
# (run* q (== q 'pea) ;; => (pea)
|
34
|
+
|
35
|
+
result = run_star('q', equals(q, :pea))
|
36
|
+
expect(result.car).to eq(:pea)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'passes frame 1:12' do
|
40
|
+
# Reasoned S2, frame 1:12
|
41
|
+
# (run* q (== 'pea q) ;; => (pea)
|
42
|
+
|
43
|
+
result = run_star('q', equals(:pea, q))
|
44
|
+
expect(result.car).to eq(:pea)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'passes frame 1:17' do
|
48
|
+
# Reasoned S2, frame 1:17
|
49
|
+
# (run* q succeed) ;; => (_0)
|
50
|
+
|
51
|
+
result = run_star('q', succeed)
|
52
|
+
expect(result.car).to eq(:_0)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'passes frame 1:19' do
|
56
|
+
# Reasoned S2, frame 1:19
|
57
|
+
# (run* q (== 'pea 'pea)) ;; => (_0)
|
58
|
+
|
59
|
+
result = run_star('q', equals(:pea, :pea))
|
60
|
+
expect(result.car).to eq(:_0)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'passes frame 1:20' do
|
64
|
+
# Reasoned S2, frame 1:20
|
65
|
+
# (run* q (== q q)) ;; => (_0)
|
66
|
+
|
67
|
+
result = run_star('q', equals(q, q))
|
68
|
+
expect(result.car).to eq(:_0)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'passes frame 1:21' do
|
72
|
+
# Reasoned S2, frame 1:21
|
73
|
+
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
74
|
+
|
75
|
+
result = run_star('q', fresh('x', equals(:pea, q)))
|
76
|
+
expect(result.car).to eq(:pea)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'passes frame 1:25' do
|
80
|
+
# Reasoned S2, frame 1:25
|
81
|
+
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
82
|
+
# require 'debug' Invalid goal argument
|
83
|
+
result = run_star('q', fresh('x', equals(cons(x, null), q)))
|
84
|
+
expect(result.car).to eq(cons(:_0))
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'passes frame 1:31' do
|
88
|
+
# Reasoned S2, frame 1:31
|
89
|
+
# (run* q (fresh (x) (== x q))) ;; => (_0)
|
90
|
+
|
91
|
+
result = run_star('q', fresh('x', equals(x, q)))
|
92
|
+
expect(result.car).to eq(:_0)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'passes frame 1:32' do
|
96
|
+
# Reasoned S2, frame 1:32
|
97
|
+
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
98
|
+
|
99
|
+
result = run_star('q', equals(cons(cons(:pea), :pod), cons(cons(:pea), :pod)))
|
100
|
+
expect(result.car).to eq(:_0)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'passes frame 1:33' do
|
104
|
+
# Beware: quasiquoting
|
105
|
+
# Reasoned S2, frame 1:33
|
106
|
+
# (run* q (== '(((pea)) pod) '(((pea)) ,q))) ;; => ('pod)
|
107
|
+
|
108
|
+
result = run_star('q', equals(cons(cons(:pea), :pod), cons(cons(:pea), q)))
|
109
|
+
expect(result.car).to eq(:pod)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'passes frame 1:34' do
|
113
|
+
# Reasoned S2, frame 1:34
|
114
|
+
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pea)
|
115
|
+
|
116
|
+
result = run_star('q', equals(cons(cons(q), :pod), cons(cons(:pea), q)))
|
117
|
+
expect(result.car).to eq(:pea)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'passes frame 1:35' do
|
121
|
+
# Reasoned S2, frame 1:35
|
122
|
+
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
123
|
+
|
124
|
+
result = run_star('q', fresh('x', equals(cons(cons(q), :pod), cons(cons(x), :pod))))
|
125
|
+
expect(result.car).to eq(:_0)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'passes frame 1:36' do
|
129
|
+
# Reasoned S2, frame 1:36
|
130
|
+
# (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
|
131
|
+
|
132
|
+
result = run_star('q', fresh('x', equals(cons(cons(cons(q)), x), cons(cons(cons(x)), :pod))))
|
133
|
+
expect(result.car).to eq(:pod)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'passes frame 1:37' do
|
137
|
+
# Reasoned S2, frame 1:37
|
138
|
+
# (run* q (fresh (x) (== '( ,x ,x) q))) ;; => (_0 _0)
|
139
|
+
|
140
|
+
result = run_star('q', fresh('x', equals(cons(x, cons(x)), q)))
|
141
|
+
expect(result.car).to eq(cons(:_0, cons(:_0)))
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'passes frame 1:38' do
|
145
|
+
# Reasoned S2, frame 1:38
|
146
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,q ,y) '((,x ,y) ,x))))) ;; => (_0 _0)
|
147
|
+
|
148
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(q, cons(y)), cons(cons(x, cons(y)), cons(x))))))
|
149
|
+
expect(result.car).to eq(cons(:_0, cons(:_0)))
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'passes frame 1:41' do
|
153
|
+
# Reasoned S2, frame 1:41
|
154
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,x ,y) q)))) ;; => (_0 _1)
|
155
|
+
|
156
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(x, cons(y)), q))))
|
157
|
+
# q should be bound to '(,x ,y)
|
158
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'passes frame 1:42' do
|
162
|
+
# Reasoned S2, frame 1:42
|
163
|
+
# (run* s (fresh (t) (fresh (u) (== '( ,t ,u) s)))) ;; => (_0 _1)
|
164
|
+
|
165
|
+
result = run_star('s', fresh('t', fresh('u', equals(cons(t, cons(u)), s))))
|
166
|
+
# s should be bound to '(,t ,u)
|
167
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'passes frame 1:43' do
|
171
|
+
# Reasoned S2, frame 1:43
|
172
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,x ,y ,x) q)))) ;; => (_0 _1 _0)
|
173
|
+
|
174
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(x, cons(y, cons(x))), q))))
|
175
|
+
# q should be bound to '(,x ,y, ,x)
|
176
|
+
expect(result.car).to eq(cons(:_0, cons(:_1, cons(:_0))))
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'passes frame 1:50' do
|
180
|
+
# Reasoned S2, frame 1:50
|
181
|
+
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
182
|
+
|
183
|
+
result = run_star('q', conj2(succeed, succeed))
|
184
|
+
expect(result.car).to eq(:_0)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'passes frame 1:51' do
|
188
|
+
# Reasoned S2, frame 1:51
|
189
|
+
# (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
|
190
|
+
|
191
|
+
result = run_star('q', conj2(succeed, equals(:corn, q)))
|
192
|
+
expect(result.car).to eq(:corn)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'passes frame 1:52' do
|
196
|
+
# Reasoned S2, frame 1:52
|
197
|
+
# (run* q (conj2 fail (== 'corn q)) ;; => ()
|
198
|
+
|
199
|
+
result = run_star('q', conj2(_fail, equals(:corn, q)))
|
200
|
+
expect(result).to be_null
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'passes frame 1:53' do
|
204
|
+
# Reasoned S2, frame 1:53
|
205
|
+
# (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
|
206
|
+
|
207
|
+
result = run_star('q', conj2(equals(:corn, q), equals(:meal, q)))
|
208
|
+
expect(result).to be_null
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'passes frame 1:54' do
|
212
|
+
# Reasoned S2, frame 1:54
|
213
|
+
# (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
|
214
|
+
|
215
|
+
result = run_star('q', conj2(equals(:corn, q), equals(:corn, q)))
|
216
|
+
expect(result.car).to eq(:corn)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'passes frame 1:55' do
|
220
|
+
# Reasoned S2, frame 1:55
|
221
|
+
# (run* q (disj2 fail fail)) ;; => ()
|
222
|
+
|
223
|
+
result = run_star('q', disj2(_fail, _fail))
|
224
|
+
expect(result).to be_null
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'passes frame 1:56' do
|
228
|
+
# Reasoned S2, frame 1:56
|
229
|
+
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
230
|
+
|
231
|
+
result = run_star('q', disj2(equals(:olive, q), _fail))
|
232
|
+
expect(result.car).to eq(:olive)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'passes frame 1:57' do
|
236
|
+
# Reasoned S2, frame 1:57
|
237
|
+
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
238
|
+
|
239
|
+
result = run_star('q', disj2(_fail, equals(:oil, q)))
|
240
|
+
expect(result.car).to eq(:oil)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'passes frame 1:58' do
|
244
|
+
# Reasoned S2, frame 1:58
|
245
|
+
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
246
|
+
|
247
|
+
result = run_star('q', disj2(equals(:olive, q), equals(:oil, q)))
|
248
|
+
expect(result.car).to eq(:olive)
|
249
|
+
expect(result.cdr.car).to eq(:oil)
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'passes frame 1:59' do
|
253
|
+
# Reasoned S2, frame 1:59
|
254
|
+
# (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
|
255
|
+
# ;; => ((_0 _1) (_0 _1))
|
256
|
+
|
257
|
+
result = run_star('q', fresh('x', (fresh 'y', disj2(equals(cons(x, cons(y)), q), equals(cons(x, cons(y)), q)))))
|
258
|
+
# q should be bound to '(,x ,y), then to '(,y ,x)
|
259
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
260
|
+
expect(result.cdr.car).to eq(cons(:_0, cons(:_1)))
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'passes frame 1:62' do
|
264
|
+
# Reasoned S2, frame 1:62
|
265
|
+
# (run* x (disj2
|
266
|
+
# (conj2 (== 'olive x) fail)
|
267
|
+
# (== 'oil x))) ;; => (oil)
|
268
|
+
|
269
|
+
result = run_star('x', disj2(conj2(equals(:olive, x), _fail), equals(:oil, x)))
|
270
|
+
expect(result.car).to eq(:oil)
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'passes frame 1:63' do
|
274
|
+
# Reasoned S2, frame 1:63
|
275
|
+
# (run* x (disj2
|
276
|
+
# (conj2 (== 'olive x) succeed)
|
277
|
+
# ('oil x))) ;; => (olive oil)
|
278
|
+
|
279
|
+
result = run_star('x', disj2(conj2(equals(:olive, x), succeed), equals(:oil, x)))
|
280
|
+
expect(result).to eq(cons(:olive, cons(:oil)))
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'passes frame 1:64' do
|
284
|
+
# Reasoned S2, frame 1:64
|
285
|
+
# (run* x (disj2
|
286
|
+
# (== 'oil x)
|
287
|
+
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
288
|
+
|
289
|
+
result = run_star('x', disj2(equals(:oil, x), conj2(equals(:olive, x), succeed)))
|
290
|
+
expect(result).to eq(cons(:oil, cons(:olive)))
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'passes frame 1:65' do
|
294
|
+
# Reasoned S2, frame 1:65
|
295
|
+
# (run* x (disj2
|
296
|
+
# (conj2(== 'virgin x) fail)
|
297
|
+
# (disj2
|
298
|
+
# (== 'olive x)
|
299
|
+
# (dis2
|
300
|
+
# succeed
|
301
|
+
# (== 'oil x))))) ;; => (olive _0 oil)
|
302
|
+
|
303
|
+
result = run_star('x', disj2(conj2(equals(:virgin, x), _fail),
|
304
|
+
disj2(equals(:olive, x), disj2(succeed, equals(:oil, x)))))
|
305
|
+
expect(result).to eq(cons(:olive, cons(:_0, cons(:oil))))
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'passes frame 1:67' do
|
309
|
+
# Reasoned S2, frame 1:67
|
310
|
+
# (run* r
|
311
|
+
# (fresh x
|
312
|
+
# (fresh y
|
313
|
+
# (conj2
|
314
|
+
# (== 'split x)
|
315
|
+
# (conj2
|
316
|
+
# (== 'pea y)
|
317
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
318
|
+
|
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))))))
|
322
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'passes frame 1:68' do
|
326
|
+
# Reasoned S2, frame 1:68
|
327
|
+
# (run* r
|
328
|
+
# (fresh x
|
329
|
+
# (fresh y
|
330
|
+
# (conj2
|
331
|
+
# (conj2
|
332
|
+
# (== 'split x)
|
333
|
+
# (== 'pea y)
|
334
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
335
|
+
|
336
|
+
result = run_star('r', fresh('x', fresh('y',
|
337
|
+
conj2(conj2(equals(:split, x), equals(:pea, y)),
|
338
|
+
equals(cons(x, cons(y)), r)))))
|
339
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'passes frame 1:70' do
|
343
|
+
# Reasoned S2, frame 1:70
|
344
|
+
# (run* r
|
345
|
+
# (fresh (x y)
|
346
|
+
# (conj2
|
347
|
+
# (conj2
|
348
|
+
# (== 'split x)
|
349
|
+
# (== 'pea y)
|
350
|
+
# (== '(,x ,y) r))))) ;; => ((split pea))
|
351
|
+
|
352
|
+
result = run_star('r', fresh(%w[x y], conj2(
|
353
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
354
|
+
equals(cons(x, cons(y)), r))))
|
355
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'passes frame 1:72' do
|
359
|
+
# Reasoned S2, frame 1:72
|
360
|
+
# (run* (r x y)
|
361
|
+
# (conj2
|
362
|
+
# (conj2
|
363
|
+
# (== 'split x)
|
364
|
+
# (== 'pea y))
|
365
|
+
# (== '(,x ,y) r))) ;; => (((split pea) split pea))
|
366
|
+
# o
|
367
|
+
# / \
|
368
|
+
# o nil
|
369
|
+
# / \
|
370
|
+
# / \
|
371
|
+
# / \
|
372
|
+
# / \
|
373
|
+
# / \
|
374
|
+
# o o
|
375
|
+
# / \ / \
|
376
|
+
# split o split o
|
377
|
+
# / \ / \
|
378
|
+
# pea nil pea nil
|
379
|
+
|
380
|
+
result = run_star(%w[r x y], conj2(
|
381
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
382
|
+
equals(cons(x, cons(y)), r)))
|
383
|
+
expect(result.car.car.car).to eq(:split)
|
384
|
+
expect(result.car.car.cdr.car).to eq(:pea)
|
385
|
+
expect(result.car.car.cdr.cdr).to be_nil
|
386
|
+
expect(result.car.cdr.car).to eq(:split)
|
387
|
+
expect(result.car.cdr.cdr.car).to eq(:pea)
|
388
|
+
expect(result.car.cdr.cdr.cdr).to be_nil
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'passes frame 1:75' do
|
392
|
+
# Reasoned S2, frame 1:75
|
393
|
+
# (run* (x y)
|
394
|
+
# (conj2
|
395
|
+
# (== 'split x)
|
396
|
+
# (== 'pea y))) ;; => ((split pea))
|
397
|
+
|
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)
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'passes frame 1:76' do
|
404
|
+
# Reasoned S2, frame 1:76
|
405
|
+
# (run* (x y)
|
406
|
+
# (disj2
|
407
|
+
# (conj2 (== 'split x) (== 'pea y))
|
408
|
+
# (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
409
|
+
|
410
|
+
result = run_star(%w[x y], disj2(
|
411
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
412
|
+
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)
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'passes frame 1:77' do
|
420
|
+
# Reasoned S2, frame 1:77
|
421
|
+
# (run* r
|
422
|
+
# (fresh (x y)
|
423
|
+
# (conj2
|
424
|
+
# (disj2
|
425
|
+
# (conj2 (== 'split x) (== 'pea y))
|
426
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
427
|
+
# (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
|
428
|
+
|
429
|
+
result = run_star('r',
|
430
|
+
fresh(%w[x y], conj2(
|
431
|
+
disj2(
|
432
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
433
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
434
|
+
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)
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'passes frame 1:78' do
|
444
|
+
# Reasoned S2, frame 1:78
|
445
|
+
# (run* r
|
446
|
+
# (fresh (x y)
|
447
|
+
# (disj2
|
448
|
+
# (conj2 (== 'split x) (== 'pea y))
|
449
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
450
|
+
# (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
|
451
|
+
|
452
|
+
result = run_star('r',
|
453
|
+
fresh(%w[x y], [disj2(
|
454
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
455
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
456
|
+
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)
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'passes frame 1:80' do
|
466
|
+
# Reasoned S2, frame 1:80
|
467
|
+
# (run* (x y z)
|
468
|
+
# (disj2
|
469
|
+
# (conj2 (== 'split x) (== 'pea y))
|
470
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
471
|
+
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
472
|
+
|
473
|
+
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)
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'passes frame 1:81' do
|
486
|
+
# Reasoned S2, frame 1:81
|
487
|
+
# (run* (x y)
|
488
|
+
# (== 'split x)
|
489
|
+
# (== 'pea y)) ;; => ((split pea))
|
490
|
+
|
491
|
+
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)
|
494
|
+
end
|
495
|
+
end # context
|
496
|
+
end # describe
|
497
|
+
end # module
|
498
|
+
end # module
|
@@ -244,7 +244,7 @@ module MiniKraken
|
|
244
244
|
instance = RunStarExpression.new('q', goal)
|
245
245
|
|
246
246
|
# Reasoned S2, frame 1:34
|
247
|
-
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('
|
247
|
+
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pea)
|
248
248
|
result = instance.run
|
249
249
|
expect(result.car).to eq(pea)
|
250
250
|
end
|
@@ -363,7 +363,6 @@ module MiniKraken
|
|
363
363
|
expect(result.car).to eq(any_value(0))
|
364
364
|
end
|
365
365
|
|
366
|
-
# TODO: fix erratic RSpec failure
|
367
366
|
it 'should support conjunction of one succeed and a successful goal' do
|
368
367
|
subgoal = equals_goal(corn, ref_q)
|
369
368
|
goal = conj2_goal(succeeds, subgoal)
|
@@ -481,7 +480,7 @@ module MiniKraken
|
|
481
480
|
# Reasoned S2, frame 1:62
|
482
481
|
# (run* x (disj2
|
483
482
|
# (conj2 (== 'olive x) fail)
|
484
|
-
# ('oil x))) ;; => (oil)
|
483
|
+
# (== 'oil x))) ;; => (oil)
|
485
484
|
result = instance.run
|
486
485
|
expect(result.car).to eq(oil)
|
487
486
|
end
|
@@ -511,7 +510,7 @@ module MiniKraken
|
|
511
510
|
|
512
511
|
# Reasoned S2, frame 1:64
|
513
512
|
# (run* x (disj2
|
514
|
-
# ('oil x)
|
513
|
+
# (== 'oil x)
|
515
514
|
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
516
515
|
result = instance.run
|
517
516
|
expect(result.car).to eq(oil)
|
@@ -530,11 +529,11 @@ module MiniKraken
|
|
530
529
|
|
531
530
|
# Reasoned S2, frame 1:65
|
532
531
|
# (run* x (disj2
|
533
|
-
# (conj2(== 'virgin x)
|
532
|
+
# (conj2(== 'virgin x) fail)
|
534
533
|
# (disj2
|
535
534
|
# (== 'olive x)
|
536
535
|
# (dis2
|
537
|
-
#
|
536
|
+
# succeed
|
538
537
|
# (== 'oil x))))) ;; => (olive _0 oil)
|
539
538
|
result = instance.run
|
540
539
|
expect(result.car).to eq(olive)
|
@@ -649,7 +648,7 @@ module MiniKraken
|
|
649
648
|
expect(result.car.cdr.cdr.cdr).to be_nil
|
650
649
|
end
|
651
650
|
|
652
|
-
it 'should allow
|
651
|
+
it 'should allow simplification of expressions' do
|
653
652
|
expr1 = equals_goal(split, ref_x)
|
654
653
|
expr2 = equals_goal(pea, ref_y)
|
655
654
|
goal = conj2_goal(expr1, expr2)
|
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.
|
4
|
+
version: 0.2.00
|
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-
|
11
|
+
date: 2020-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- lib/mini_kraken/core/variable.rb
|
105
105
|
- lib/mini_kraken/core/variable_ref.rb
|
106
106
|
- lib/mini_kraken/core/vocabulary.rb
|
107
|
+
- lib/mini_kraken/glue/dsl.rb
|
107
108
|
- lib/mini_kraken/glue/fresh_env.rb
|
108
109
|
- lib/mini_kraken/glue/run_star_expression.rb
|
109
110
|
- lib/mini_kraken/version.rb
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- spec/core/variable_ref_spec.rb
|
129
130
|
- spec/core/variable_spec.rb
|
130
131
|
- spec/core/vocabulary_spec.rb
|
132
|
+
- spec/glue/dsl_chap1_spec.rb
|
131
133
|
- spec/glue/fresh_env_spec.rb
|
132
134
|
- spec/glue/run_star_expression_spec.rb
|
133
135
|
- spec/mini_kraken_spec.rb
|
@@ -178,6 +180,7 @@ test_files:
|
|
178
180
|
- spec/core/variable_ref_spec.rb
|
179
181
|
- spec/core/variable_spec.rb
|
180
182
|
- spec/core/vocabulary_spec.rb
|
183
|
+
- spec/glue/dsl_chap1_spec.rb
|
181
184
|
- spec/glue/fresh_env_spec.rb
|
182
185
|
- spec/glue/run_star_expression_spec.rb
|
183
186
|
- spec/mini_kraken_spec.rb
|