rubylog 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|