rubylog 0.0.1 → 1.0.0
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.
- data/Gemfile +1 -1
- data/README.hu.rb +58 -0
- data/README.rdoc +248 -89
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/rubylog +18 -0
- data/examples/dcg.rb +35 -0
- data/examples/dcg2.rb +42 -0
- data/examples/enumerators.rb +30 -0
- data/examples/factorial.rb +9 -8
- data/examples/hanoi.rb +24 -0
- data/examples/hello.rb +11 -5
- data/examples/parsing.rb +27 -0
- data/examples/primitives.rb +24 -0
- data/examples/theory.rb +22 -10
- data/lib/rubylog/builtins/default.rb +10 -0
- data/lib/rubylog/builtins/file_system.rb +15 -0
- data/lib/rubylog/builtins/logic.rb +109 -0
- data/lib/rubylog/builtins/reflection.rb +94 -0
- data/lib/rubylog/builtins/term.rb +47 -0
- data/lib/rubylog/dsl/array_splat.rb +25 -0
- data/lib/rubylog/dsl/primitives.rb +17 -0
- data/lib/rubylog/dsl/thats.rb +22 -0
- data/lib/rubylog/dsl/variables.rb +30 -0
- data/lib/rubylog/dsl.rb +35 -17
- data/lib/rubylog/errors.rb +19 -1
- data/lib/rubylog/interfaces/assertable.rb +16 -0
- data/lib/rubylog/interfaces/callable.rb +18 -0
- data/lib/rubylog/interfaces/composite_term.rb +47 -0
- data/lib/rubylog/interfaces/predicate.rb +8 -0
- data/lib/rubylog/interfaces/procedure.rb +60 -0
- data/lib/rubylog/interfaces/term.rb +41 -0
- data/lib/rubylog/mixins/array.rb +118 -0
- data/lib/{class.rb → rubylog/mixins/class.rb} +2 -2
- data/lib/rubylog/mixins/hash.rb +8 -0
- data/lib/rubylog/mixins/kernel.rb +5 -0
- data/lib/rubylog/mixins/method.rb +3 -0
- data/lib/rubylog/mixins/object.rb +8 -0
- data/lib/rubylog/mixins/proc.rb +37 -0
- data/lib/rubylog/mixins/string.rb +104 -0
- data/lib/rubylog/mixins/symbol.rb +44 -0
- data/lib/rubylog/simple_procedure.rb +8 -0
- data/lib/rubylog/{clause.rb → structure.rb} +32 -31
- data/lib/rubylog/theory.rb +368 -79
- data/lib/rubylog/variable.rb +102 -23
- data/lib/rubylog.rb +33 -25
- data/logic/builtins/file_system_logic.rb +23 -0
- data/logic/builtins/reflection_logic.rb +40 -0
- data/logic/dereference_logic.rb +23 -0
- data/logic/directory_structure_logic.rb +19 -0
- data/logic/dsl_logic.rb +29 -0
- data/logic/errors_logic.rb +9 -0
- data/logic/guard_logic.rb +115 -0
- data/logic/list_logic.rb +55 -0
- data/logic/map_logic.rb +15 -0
- data/logic/multitheory.rb +23 -0
- data/logic/recursion_logic.rb +12 -0
- data/logic/string_logic.rb +41 -0
- data/logic/thats_logic.rb +51 -0
- data/logic/variable_logic.rb +24 -0
- data/rubylog.gemspec +85 -46
- data/spec/bartak_guide_spec.rb +57 -62
- data/spec/builtins/all_spec.rb +99 -0
- data/spec/builtins/and_spec.rb +22 -0
- data/spec/builtins/array_spec.rb +16 -0
- data/spec/builtins/branch_or_spec.rb +27 -0
- data/spec/builtins/cut_spec.rb +44 -0
- data/spec/builtins/fail_spec.rb +5 -0
- data/spec/builtins/false_spec.rb +5 -0
- data/spec/builtins/in_spec.rb +38 -0
- data/spec/builtins/is_false_spec.rb +12 -0
- data/spec/builtins/is_spec.rb +26 -0
- data/spec/builtins/matches_spec.rb +23 -0
- data/spec/builtins/or_spec.rb +22 -0
- data/spec/{rubylog/builtins → builtins}/splits_to.rb +0 -0
- data/spec/builtins/then_spec.rb +27 -0
- data/spec/builtins/true_spec.rb +5 -0
- data/spec/clause_spec.rb +82 -0
- data/spec/compilation_spec.rb +61 -0
- data/spec/custom_classes_spec.rb +43 -0
- data/spec/dereference.rb +10 -0
- data/spec/{inriasuite.rb → inriasuite_spec.rb} +2 -9
- data/spec/queries_spec.rb +150 -0
- data/spec/recursion_spec.rb +4 -4
- data/spec/ruby_code_spec.rb +52 -0
- data/spec/rules_spec.rb +97 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/theory_spec.rb +28 -0
- data/spec/unification_spec.rb +84 -0
- data/spec/variable_spec.rb +26 -0
- metadata +153 -180
- data/examples/4queens.rb +0 -10
- data/examples/calculation.rb +0 -12
- data/examples/concepts.rb +0 -46
- data/examples/fp.rb +0 -56
- data/examples/historia_de_espana.rb +0 -31
- data/examples/idea.rb +0 -143
- data/examples/lists.rb +0 -5
- data/examples/mechanika.rb +0 -409
- data/examples/parse.rb +0 -15
- data/lib/array.rb +0 -24
- data/lib/method.rb +0 -4
- data/lib/object.rb +0 -5
- data/lib/proc.rb +0 -4
- data/lib/rubylog/builtins.rb +0 -193
- data/lib/rubylog/callable.rb +0 -20
- data/lib/rubylog/composite_term.rb +0 -38
- data/lib/rubylog/dsl/constants.rb +0 -15
- data/lib/rubylog/dsl/first_order_functors.rb +0 -9
- data/lib/rubylog/dsl/global_functors.rb +0 -3
- data/lib/rubylog/dsl/second_order_functors.rb +0 -8
- data/lib/rubylog/internal_helpers.rb +0 -16
- data/lib/rubylog/predicate.rb +0 -34
- data/lib/rubylog/proc_method_additions.rb +0 -69
- data/lib/rubylog/term.rb +0 -20
- data/lib/rubylog/unifiable.rb +0 -19
- data/lib/symbol.rb +0 -35
- data/script/inriasuite2spec +0 -0
- data/script/inriasuite2spec.pl +0 -22
- data/spec/rubylog/clause_spec.rb +0 -81
- data/spec/rubylog/variable_spec.rb +0 -25
- data/spec/rubylog_spec.rb +0 -914
data/Gemfile
CHANGED
data/README.hu.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Rubylog
|
2
|
+
|
3
|
+
# A Rubylog a Prologhoz hasonló programozási nyelv.
|
4
|
+
|
5
|
+
# A Prolog program alapköve a funktorból és argumentumokból álló term:
|
6
|
+
likes("John", "beer")
|
7
|
+
|
8
|
+
# A Rubylog programban a funktor az első argumentum után áll:
|
9
|
+
"John".likes("beer")
|
10
|
+
|
11
|
+
# A prolog programot tények és szabályok alkotják.
|
12
|
+
likes("John", "beer").
|
13
|
+
drinks(X,D) :- likes(X,D).
|
14
|
+
|
15
|
+
# Rubylogban hasonlóan, a tényeket ! jelzi, a szabályokat 'if'
|
16
|
+
"John".likes! "beer"
|
17
|
+
X.drinks(D).if X.likes(D)
|
18
|
+
|
19
|
+
# A nulláris predikátumok a Rubylogban szimbólumok:
|
20
|
+
:true
|
21
|
+
:fail
|
22
|
+
:cut!
|
23
|
+
|
24
|
+
# A Prolog operátorok helyett Rubylogban sokszor szavakat használunk:
|
25
|
+
# Prolog Rubylog
|
26
|
+
:- if
|
27
|
+
, and
|
28
|
+
; or
|
29
|
+
\+ false
|
30
|
+
= is
|
31
|
+
|
32
|
+
# A jobb hangzás érdekében néhány Prolog beépített predikátum neve más
|
33
|
+
# Rubylogban
|
34
|
+
# Prolog Rubylog
|
35
|
+
member in
|
36
|
+
# HAsonlít de többet tud
|
37
|
+
|
38
|
+
# Vannak
|
39
|
+
all
|
40
|
+
any
|
41
|
+
one
|
42
|
+
none
|
43
|
+
|
44
|
+
# Reflection
|
45
|
+
list structure follows_from
|
46
|
+
|
47
|
+
|
48
|
+
# Azért nem vezettünk be
|
49
|
+
{a:b}.is {a}
|
50
|
+
{}.isnt {a:b}
|
51
|
+
# -t, mert akkor nem lenne kummutatív az unifikáció, és az egyáltalán nem POLA.
|
52
|
+
# Azért nem vezettünk be
|
53
|
+
{a:b}.is {}
|
54
|
+
# -t, mert az nagyon bonyolult, és nem POLA. Ezért marad
|
55
|
+
{a:b}.is {a:b}
|
56
|
+
# és lehet
|
57
|
+
{a:b}.merge!(X)
|
58
|
+
# akár.
|
data/README.rdoc
CHANGED
@@ -1,101 +1,260 @@
|
|
1
1
|
= Rubylog - Prolog interpreter for ruby
|
2
2
|
|
3
|
-
Rubylog is
|
3
|
+
Rubylog is a Prolog-like DSL for Ruby. The language is inspired by {Jamis
|
4
|
+
Buck}[http://weblog.jamisbuck.org/2006/10/28/prolog-in-ruby], and the
|
5
|
+
implementation is based on {Yield Prolog}[http://yieldprolog.sourceforge.net/],
|
6
|
+
with lots of sintactic and semantic additions.
|
7
|
+
|
8
|
+
== Getting started
|
9
|
+
|
10
|
+
First, install the gem
|
4
11
|
|
5
|
-
== Installing
|
6
12
|
$ gem install rubylog
|
7
13
|
|
8
|
-
|
14
|
+
or, if you use +bundler+, add this line to your +Gemfile+:
|
15
|
+
|
16
|
+
gem 'rubylog', '~>1.0.0'
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
First, you have to create a theory and write your code in the block given to it:
|
9
21
|
|
10
|
-
To get started you have to do three things: require rubylog, include Rubylog::DSL::Constants and declare some functors on a class you want to use:
|
11
22
|
require 'rubylog'
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
X.drinks(Y).if Y.
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
!
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
A
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
23
|
+
|
24
|
+
MyTheory = theory do
|
25
|
+
# your code here
|
26
|
+
end
|
27
|
+
|
28
|
+
All further examples in this file should be written within the +theory+ block.
|
29
|
+
|
30
|
+
|
31
|
+
=== Data types
|
32
|
+
|
33
|
+
Rubylog is similar to Prolog, but there are quite a few differences. In Rubylog,
|
34
|
+
you can use any Ruby object as data.
|
35
|
+
|
36
|
+
Rubylog variables are (undefined) constant names:
|
37
|
+
|
38
|
+
A, B, ANYTHING
|
39
|
+
|
40
|
+
A variables whose name starts with +ANY...+ (case-insensitive) is a don't-care
|
41
|
+
variable (like +_+ in Prolog).
|
42
|
+
|
43
|
+
Structures are in a different order than they are in prolog:
|
44
|
+
|
45
|
+
functor_for String, :likes
|
46
|
+
'John'.likes('beer')
|
47
|
+
|
48
|
+
which would be +likes('John','beer')+ in prolog.
|
49
|
+
|
50
|
+
Lists are just Ruby arrays:
|
51
|
+
|
52
|
+
[1, 2, 3]
|
53
|
+
|
54
|
+
They can have splats:
|
55
|
+
|
56
|
+
[1, 2, *T]
|
57
|
+
|
58
|
+
Which would be +[1,2|T]+ in Prolog, however, in Rubylog, splats are not limited
|
59
|
+
to the end.
|
60
|
+
|
61
|
+
=== Predicates
|
62
|
+
|
63
|
+
You can assert a rule with the +if+ method:
|
64
|
+
|
65
|
+
X.drinks(Y).if X.has(Y).and X.likes(Y)
|
66
|
+
|
67
|
+
This would be +drinks(X,Y) :- has(X,Y), likes(X,Y)+ in Prolog.
|
68
|
+
|
69
|
+
You can assert facts with +if(:true)+, or, as a shorthand you can use the bang
|
70
|
+
syntax:
|
71
|
+
|
72
|
+
'John'.likes! 'milk'
|
73
|
+
|
74
|
+
Bang assertions return their first argument (which is +'John'+ in this case), so they can be chained:
|
75
|
+
|
76
|
+
'John'.likes!('beer').has!('beer')
|
77
|
+
|
78
|
+
You can also use +unless+:
|
79
|
+
|
80
|
+
A.good.unless A.bad
|
81
|
+
|
82
|
+
Nullary predicates are symbols, similar to Prolog:
|
83
|
+
|
84
|
+
'John'.drinks('beer').if :false.and(:cut!).or(:true)
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
=== Built-in predicates
|
89
|
+
|
90
|
+
Some built-in predicates and their Prolog equivalents:
|
91
|
+
|
92
|
+
Rubylog Prolog
|
93
|
+
------- ------
|
94
|
+
:true true
|
95
|
+
:fail fail
|
96
|
+
.and ,
|
97
|
+
.or ;
|
98
|
+
:false \+
|
99
|
+
.is =
|
100
|
+
.is_not =/=
|
101
|
+
.in member
|
102
|
+
:cut! !
|
103
|
+
|
104
|
+
There are some new ones:
|
105
|
+
|
106
|
+
is_not, not_in, all, any, one, none, iff
|
107
|
+
|
108
|
+
=== Unification
|
109
|
+
|
110
|
+
In Rubylog, unification works quite the same in Prolog, with the +is+ functor.
|
111
|
+
|
112
|
+
A.is(B)
|
113
|
+
|
114
|
+
Using arrays, you can benefit the splats:
|
115
|
+
|
116
|
+
[1,2,3,4].is([A,B,*T]) # [1,2,3,4] = [A,B|T] in prolog
|
117
|
+
[1,2,3,4].is([*H,*T]) # append(H, T, [1,2,3,4]) in prolog
|
118
|
+
|
119
|
+
The +in+ predicate unifies the first argument with any member of the collection:
|
120
|
+
|
121
|
+
4.in([1,2,3,4])
|
122
|
+
|
123
|
+
You can use guards:
|
124
|
+
|
125
|
+
A[String].in(["asdf",5,nil]).each { p A } # outputs "asdf"
|
126
|
+
A[/x/].in(["asdf","xyz"]).each { p A } # outputs "xyz"
|
127
|
+
A[thats < 5].in([4,5,6]).each { p A } # outputs 4
|
128
|
+
|
129
|
+
=== Moving between Ruby and Rubylog
|
130
|
+
==== Running a query
|
131
|
+
|
132
|
+
If you want to run a query, you have many different syntaxes:
|
133
|
+
|
134
|
+
prove ('John'.drinks 'beer') # => true
|
135
|
+
true? ('John'.drinks 'beer') # => true
|
136
|
+
('John'.drinks 'beer').true? # => true
|
137
|
+
'John'.drinks? 'beer' # => true
|
138
|
+
|
139
|
+
==== Enumerations
|
140
|
+
|
141
|
+
+Structure+ implements +Enumerable+, and yields the solutions. Within the
|
142
|
+
enumeration block, you can access the values of your variables.
|
143
|
+
|
144
|
+
'John'.drinks! 'beer'
|
145
|
+
('John'.drinks X).each {p X} # outputs 'beer'
|
146
|
+
('John'.drinks X).map{X} # => ['beer']
|
147
|
+
('John'.drinks X).count # => 1
|
148
|
+
|
149
|
+
==== Procs as predicates
|
150
|
+
|
151
|
+
You can invoke Ruby codes in Rubylog rules with a proc:
|
152
|
+
|
153
|
+
'John'.likes(Y).if proc{ Y =~ /ale/ }
|
154
|
+
|
155
|
+
or in most cases you can use just a block:
|
156
|
+
|
157
|
+
'John'.likes(Y).if { Y =~ /ale/ }
|
158
|
+
|
159
|
+
The predicate succeeds if the block returns a true value.
|
160
|
+
|
161
|
+
==== Procs as functions
|
162
|
+
|
163
|
+
+is+ and +in+ can take a proc or block argument, which they execute and take its return value:
|
164
|
+
|
165
|
+
X.good.if X.is { 'BEER'.downcase }
|
166
|
+
X.good.if X.in { get_good_drinks() }
|
167
|
+
|
168
|
+
==== The two modes of Rubylog
|
169
|
+
|
170
|
+
Rubylog has two modes, DSL and native. DSL code is executed only once
|
171
|
+
at compile time, and is used for describing the Rubylog program. Native code is
|
172
|
+
executed runtime. Any block passed to Rubylog structures native code.
|
173
|
+
|
174
|
+
('John'.drinks X).and { X != 'beer'}.each { p X }
|
175
|
+
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ dsl mode
|
176
|
+
^^^^^^^^^^^^ ^^^^^ native mode
|
177
|
+
|
178
|
+
In dsl mode, variables are +Rubylog::Variable+ objects. In native mode,
|
179
|
+
variables are substituted with their respecitve value (or +nil+ if they are not
|
180
|
+
bound).
|
181
|
+
|
182
|
+
All built-in rubylog predicates are clean logical programming predicates witout
|
183
|
+
a side-effect. If you want some side-effect, you always go into native mode.
|
184
|
+
|
185
|
+
=== Rubylog as a test suite
|
186
|
+
|
187
|
+
You can write simple tests using the +check+ method:
|
188
|
+
|
189
|
+
theory do
|
190
|
+
check :true
|
191
|
+
check { 5+5 == 10 }
|
192
|
+
end
|
193
|
+
|
194
|
+
You sould put this file in +"./logic/something\_logic.rb"+. Then you can run it
|
195
|
+
with
|
196
|
+
|
197
|
+
rubylog logic/something_logic.rb
|
198
|
+
|
199
|
+
Or you can run all files in +logic/**/*_logic.rb+ with
|
200
|
+
|
201
|
+
rubylog
|
202
|
+
|
203
|
+
=== Other built-in libraries
|
204
|
+
|
205
|
+
==== File system
|
206
|
+
|
207
|
+
You can make some queries on the file system:
|
208
|
+
|
209
|
+
require "rubylog/builtins/file_system"
|
210
|
+
|
211
|
+
theory do
|
212
|
+
check "README".filename_in "."
|
213
|
+
|
214
|
+
X.dirname_in(".").each { puts X }
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
==== Reflection
|
219
|
+
|
220
|
+
You can make some metaprogramming with Rubylog
|
221
|
+
|
222
|
+
|
223
|
+
require "rubylog/builtins/reflection"
|
224
|
+
|
225
|
+
theory do
|
226
|
+
functor_for String, :likes
|
227
|
+
|
228
|
+
check "John".likes("Jane").structure(:likes, ["John", "Jane"])
|
229
|
+
|
230
|
+
"John".likes(X).if X.likes("John")
|
231
|
+
"Jane".likes!("John")
|
232
|
+
check "John".likes("Jane").follows_from "Jane".likes("John")
|
233
|
+
|
234
|
+
"John".likes!("milk")
|
235
|
+
check "John".likes("milk").fact
|
236
|
+
check "John".likes("beer").fact.false
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
== Contributing
|
241
|
+
|
242
|
+
=== To the language
|
243
|
+
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
|
244
|
+
* We will discuss it.
|
245
|
+
* Maybe I'll introduce it.
|
246
|
+
|
247
|
+
=== To the implementation
|
248
|
+
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
|
249
|
+
* We will discuss it.
|
250
|
+
* Maybe I'll implement it.
|
251
|
+
* If not, fork the project.
|
252
|
+
* Implement it.
|
253
|
+
* Have fun.
|
254
|
+
* Post a pull request.
|
96
255
|
|
97
256
|
== Copyright
|
98
257
|
|
99
|
-
Copyright (c)
|
258
|
+
Copyright (c) 2013 Bernát Kalló. See LICENSE.txt for
|
100
259
|
further details.
|
101
260
|
|
data/Rakefile
CHANGED
@@ -21,6 +21,7 @@ Jeweler::Tasks.new do |gem|
|
|
21
21
|
gem.description = %Q{Rubylog is an embedded Prolog language and interpreter for Ruby.}
|
22
22
|
gem.email = "kallo.bernat@gmail.com"
|
23
23
|
gem.authors = ["Bernát Kalló"]
|
24
|
+
gem.executables = Dir["bin/*"].map{|x|File.basename x}
|
24
25
|
# dependencies defined in Gemfile
|
25
26
|
end
|
26
27
|
Jeweler::RubygemsDotOrgTasks.new
|
@@ -47,7 +48,11 @@ RoodiTask.new do |t|
|
|
47
48
|
t.verbose = false
|
48
49
|
end
|
49
50
|
|
50
|
-
task :
|
51
|
+
task :logic do
|
52
|
+
run "ruby"
|
53
|
+
end
|
54
|
+
|
55
|
+
task :default => :logic
|
51
56
|
|
52
57
|
require 'yard'
|
53
58
|
YARD::Rake::YardocTask.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
1.0.0
|
data/bin/rubylog
ADDED
data/examples/dcg.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# This is a quick and dirty solution to replace Prolog's DCG syntax.
|
2
|
+
# It is slow for long inputs. See examples/dcg2.rb for a more efficient algorithm (the same as Prolog's DCG).
|
3
|
+
|
4
|
+
theory do
|
5
|
+
functor_for Array, :sentence, :subject, :object, :nominal_phrase, :noun, :verb, :article
|
6
|
+
|
7
|
+
[*S,*V,*O].sentence.if S.subject.and V.verb.and O.object
|
8
|
+
S.subject.if S.nominal_phrase
|
9
|
+
O.object .if O.nominal_phrase
|
10
|
+
[*A,*N].nominal_phrase.if A.article.and N.noun
|
11
|
+
|
12
|
+
%w(a).article!
|
13
|
+
%w(the).article!
|
14
|
+
|
15
|
+
%w(dog).noun!
|
16
|
+
%w(cat).noun!
|
17
|
+
%w(mouse).noun!
|
18
|
+
|
19
|
+
%w(chases).verb!
|
20
|
+
%w(eats).verb!
|
21
|
+
|
22
|
+
def check_passed goal; end
|
23
|
+
|
24
|
+
check %w(dog).noun
|
25
|
+
check %w(a dog).nominal_phrase
|
26
|
+
check %w(dog).nominal_phrase.false
|
27
|
+
check %w(the dog chases a cat).sentence
|
28
|
+
check %w(the dog chases a cat stuff).sentence.false
|
29
|
+
check %w(dog chases cat).sentence.false
|
30
|
+
check { %W(the #{S} chases the #{O}).sentence.map{[S,O]}.count == 9 }
|
31
|
+
|
32
|
+
puts *S.sentence.map{S.join(" ")}
|
33
|
+
|
34
|
+
|
35
|
+
end
|
data/examples/dcg2.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# This is an example of the same algorithm that Prolog's DCG syntax generates.
|
2
|
+
#
|
3
|
+
|
4
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
5
|
+
require 'rubylog'
|
6
|
+
|
7
|
+
theory do
|
8
|
+
functor_for Array, :sentence, :subject, :object, :nominal_phrase, :noun, :verb, :article
|
9
|
+
|
10
|
+
# sentence --> subject, verb, object
|
11
|
+
Se.sentence(L3).if Se.subject(L1).and L1.verb(L2).and L2.object(L3)
|
12
|
+
# subject --> nominal_phrase
|
13
|
+
S.subject(L1).if S.nominal_phrase(L1)
|
14
|
+
# object --> nominal_phrase
|
15
|
+
O.object(L1) .if O.nominal_phrase(L1)
|
16
|
+
# nominal_phrase --> article, noun
|
17
|
+
N.nominal_phrase(L2).if N.article(L1).and L1.noun(L2)
|
18
|
+
|
19
|
+
["a",*L1].article! L1
|
20
|
+
["the",*L1].article! L1
|
21
|
+
|
22
|
+
["dog",*L1].noun! L1
|
23
|
+
["cat",*L1].noun! L1
|
24
|
+
["mouse",*L1].noun! L1
|
25
|
+
|
26
|
+
["chases",*L1].verb! L1
|
27
|
+
["eats",*L1].verb! L1
|
28
|
+
|
29
|
+
def check_passed goal; end
|
30
|
+
|
31
|
+
check %w(dog).noun([])
|
32
|
+
check %w(a dog).nominal_phrase([])
|
33
|
+
check %w(dog).nominal_phrase(ANY).false
|
34
|
+
check %w(the dog chases a cat).sentence([])
|
35
|
+
check %w(the dog chases a cat stuff).sentence(["stuff"])
|
36
|
+
check %w(dog chases cat).sentence(ANY).false
|
37
|
+
check { %W(the #{S} chases the #{O}).sentence([]).map{[S,O]}.count == 9 }
|
38
|
+
|
39
|
+
puts *S.sentence([]).map{S.join(" ")}
|
40
|
+
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
2
|
+
require 'rubylog'
|
3
|
+
|
4
|
+
theory do
|
5
|
+
subject Symbol
|
6
|
+
functor :likes
|
7
|
+
|
8
|
+
:john.likes! :beer
|
9
|
+
:john.likes! :milk
|
10
|
+
:john.likes! :water
|
11
|
+
|
12
|
+
:jane.likes! :milk
|
13
|
+
:jane.likes! :water
|
14
|
+
|
15
|
+
:jeff.likes! :water
|
16
|
+
:jeff.likes! :milk
|
17
|
+
:jeff.likes! :juice
|
18
|
+
|
19
|
+
check A.likes(:beer).all A.likes(:water)
|
20
|
+
check A.likes(:beer).any A.likes(B).and B.is_not :water
|
21
|
+
check A.likes(:milk).iff A.likes(:water)
|
22
|
+
check A.likes(:beer).iff A.is(:john)
|
23
|
+
|
24
|
+
check all(X.likes(:juice), X.likes(:beer).false)
|
25
|
+
check any(X.likes(:water), X.likes(:juice))
|
26
|
+
check one(X.likes :juice)
|
27
|
+
check one(X.likes :milk).false
|
28
|
+
check none(X.likes :palinka)
|
29
|
+
check iff A.likes(:milk), A.likes(:water)
|
30
|
+
end
|
data/examples/factorial.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
1
2
|
require 'rubylog'
|
2
3
|
|
3
|
-
|
4
|
+
FactorialTheory = theory do
|
5
|
+
subject Integer
|
6
|
+
functor :factorial
|
4
7
|
|
5
8
|
0.factorial! 1
|
6
|
-
N
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
Integer.include_theory self
|
9
|
+
N[thats > 0].factorial(K).if \
|
10
|
+
N1.is{N-1}.
|
11
|
+
and N1.factorial(K1).
|
12
|
+
and K.is{N*K1}
|
13
13
|
|
14
|
+
7.factorial(N).solve {puts N}
|
14
15
|
end
|
15
16
|
|
16
17
|
|
data/examples/hanoi.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
2
|
+
require "rubylog"
|
3
|
+
|
4
|
+
theory do
|
5
|
+
functor_for Integer, :move, :hanoi
|
6
|
+
prefix_functor :write_info
|
7
|
+
|
8
|
+
0.move(ANY,ANY,ANY).if :cut!
|
9
|
+
N.move(A,B,C).if (
|
10
|
+
M.is{N-1}.and \
|
11
|
+
M.move(A,C,B).and \
|
12
|
+
{ puts "move disc #{N} from the #{A} pole to the #{B} pole" or true }.and \
|
13
|
+
M.move(C,B,A)
|
14
|
+
)
|
15
|
+
N.hanoi.if N.move('left', 'right', 'center')
|
16
|
+
|
17
|
+
puts "\nWhat's the solution for a single disc?"
|
18
|
+
prove 1.hanoi
|
19
|
+
|
20
|
+
puts "\n\nWhat's the solution for 5 discs?"
|
21
|
+
prove 5.hanoi
|
22
|
+
|
23
|
+
|
24
|
+
end
|
data/examples/hello.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
2
2
|
|
3
|
-
|
3
|
+
require 'rubylog'
|
4
4
|
|
5
|
-
A.write.if {|a| puts a; true}
|
6
|
-
:hello.if "Hello, world!".write
|
7
5
|
|
8
|
-
|
6
|
+
HelloTheory = theory do
|
7
|
+
functor_for String, :written
|
8
|
+
|
9
|
+
X.written.if {puts X; true}
|
10
|
+
|
11
|
+
:hello.if "Hello, world!".written
|
12
|
+
end
|
13
|
+
|
14
|
+
HelloTheory.prove :hello
|
9
15
|
|
data/examples/parsing.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "readline"
|
2
|
+
|
3
|
+
theory do
|
4
|
+
functor_for String, :term, :expr, :atom
|
5
|
+
|
6
|
+
"#{A}+#{B}".expr(K).if A.term(I).and B.expr(J).and K.is{I+J}
|
7
|
+
"#{A}-#{B}".expr(K).if A.term(I).and B.expr(J).and K.is{I-J}
|
8
|
+
A.expr(K).if A.term(K)
|
9
|
+
"#{A}*#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I*J}
|
10
|
+
"#{A}/#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I/J}
|
11
|
+
A.term(K).if A.atom(K)
|
12
|
+
A[/\A[0-9]+\z/].atom(K).if K.is{A.to_i}
|
13
|
+
"(#{A})".atom(K).if A.expr(K)
|
14
|
+
|
15
|
+
check "5".expr(5)
|
16
|
+
check "5+3*2".expr(11)
|
17
|
+
check "1+2+3+4".expr(10)
|
18
|
+
check "(5+3)/2".expr(4)
|
19
|
+
check "(5+3(5)/2".expr(ANY).false
|
20
|
+
|
21
|
+
puts
|
22
|
+
while k = Readline.readline("> ", true)
|
23
|
+
k.chomp!
|
24
|
+
puts k.expr(X).map{X}.first || "error"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|