rubylog 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Gemfile +1 -1
  2. data/README.hu.rb +58 -0
  3. data/README.rdoc +248 -89
  4. data/Rakefile +6 -1
  5. data/VERSION +1 -1
  6. data/bin/rubylog +18 -0
  7. data/examples/dcg.rb +35 -0
  8. data/examples/dcg2.rb +42 -0
  9. data/examples/enumerators.rb +30 -0
  10. data/examples/factorial.rb +9 -8
  11. data/examples/hanoi.rb +24 -0
  12. data/examples/hello.rb +11 -5
  13. data/examples/parsing.rb +27 -0
  14. data/examples/primitives.rb +24 -0
  15. data/examples/theory.rb +22 -10
  16. data/lib/rubylog/builtins/default.rb +10 -0
  17. data/lib/rubylog/builtins/file_system.rb +15 -0
  18. data/lib/rubylog/builtins/logic.rb +109 -0
  19. data/lib/rubylog/builtins/reflection.rb +94 -0
  20. data/lib/rubylog/builtins/term.rb +47 -0
  21. data/lib/rubylog/dsl/array_splat.rb +25 -0
  22. data/lib/rubylog/dsl/primitives.rb +17 -0
  23. data/lib/rubylog/dsl/thats.rb +22 -0
  24. data/lib/rubylog/dsl/variables.rb +30 -0
  25. data/lib/rubylog/dsl.rb +35 -17
  26. data/lib/rubylog/errors.rb +19 -1
  27. data/lib/rubylog/interfaces/assertable.rb +16 -0
  28. data/lib/rubylog/interfaces/callable.rb +18 -0
  29. data/lib/rubylog/interfaces/composite_term.rb +47 -0
  30. data/lib/rubylog/interfaces/predicate.rb +8 -0
  31. data/lib/rubylog/interfaces/procedure.rb +60 -0
  32. data/lib/rubylog/interfaces/term.rb +41 -0
  33. data/lib/rubylog/mixins/array.rb +118 -0
  34. data/lib/{class.rb → rubylog/mixins/class.rb} +2 -2
  35. data/lib/rubylog/mixins/hash.rb +8 -0
  36. data/lib/rubylog/mixins/kernel.rb +5 -0
  37. data/lib/rubylog/mixins/method.rb +3 -0
  38. data/lib/rubylog/mixins/object.rb +8 -0
  39. data/lib/rubylog/mixins/proc.rb +37 -0
  40. data/lib/rubylog/mixins/string.rb +104 -0
  41. data/lib/rubylog/mixins/symbol.rb +44 -0
  42. data/lib/rubylog/simple_procedure.rb +8 -0
  43. data/lib/rubylog/{clause.rb → structure.rb} +32 -31
  44. data/lib/rubylog/theory.rb +368 -79
  45. data/lib/rubylog/variable.rb +102 -23
  46. data/lib/rubylog.rb +33 -25
  47. data/logic/builtins/file_system_logic.rb +23 -0
  48. data/logic/builtins/reflection_logic.rb +40 -0
  49. data/logic/dereference_logic.rb +23 -0
  50. data/logic/directory_structure_logic.rb +19 -0
  51. data/logic/dsl_logic.rb +29 -0
  52. data/logic/errors_logic.rb +9 -0
  53. data/logic/guard_logic.rb +115 -0
  54. data/logic/list_logic.rb +55 -0
  55. data/logic/map_logic.rb +15 -0
  56. data/logic/multitheory.rb +23 -0
  57. data/logic/recursion_logic.rb +12 -0
  58. data/logic/string_logic.rb +41 -0
  59. data/logic/thats_logic.rb +51 -0
  60. data/logic/variable_logic.rb +24 -0
  61. data/rubylog.gemspec +85 -46
  62. data/spec/bartak_guide_spec.rb +57 -62
  63. data/spec/builtins/all_spec.rb +99 -0
  64. data/spec/builtins/and_spec.rb +22 -0
  65. data/spec/builtins/array_spec.rb +16 -0
  66. data/spec/builtins/branch_or_spec.rb +27 -0
  67. data/spec/builtins/cut_spec.rb +44 -0
  68. data/spec/builtins/fail_spec.rb +5 -0
  69. data/spec/builtins/false_spec.rb +5 -0
  70. data/spec/builtins/in_spec.rb +38 -0
  71. data/spec/builtins/is_false_spec.rb +12 -0
  72. data/spec/builtins/is_spec.rb +26 -0
  73. data/spec/builtins/matches_spec.rb +23 -0
  74. data/spec/builtins/or_spec.rb +22 -0
  75. data/spec/{rubylog/builtins → builtins}/splits_to.rb +0 -0
  76. data/spec/builtins/then_spec.rb +27 -0
  77. data/spec/builtins/true_spec.rb +5 -0
  78. data/spec/clause_spec.rb +82 -0
  79. data/spec/compilation_spec.rb +61 -0
  80. data/spec/custom_classes_spec.rb +43 -0
  81. data/spec/dereference.rb +10 -0
  82. data/spec/{inriasuite.rb → inriasuite_spec.rb} +2 -9
  83. data/spec/queries_spec.rb +150 -0
  84. data/spec/recursion_spec.rb +4 -4
  85. data/spec/ruby_code_spec.rb +52 -0
  86. data/spec/rules_spec.rb +97 -0
  87. data/spec/spec_helper.rb +6 -2
  88. data/spec/theory_spec.rb +28 -0
  89. data/spec/unification_spec.rb +84 -0
  90. data/spec/variable_spec.rb +26 -0
  91. metadata +153 -180
  92. data/examples/4queens.rb +0 -10
  93. data/examples/calculation.rb +0 -12
  94. data/examples/concepts.rb +0 -46
  95. data/examples/fp.rb +0 -56
  96. data/examples/historia_de_espana.rb +0 -31
  97. data/examples/idea.rb +0 -143
  98. data/examples/lists.rb +0 -5
  99. data/examples/mechanika.rb +0 -409
  100. data/examples/parse.rb +0 -15
  101. data/lib/array.rb +0 -24
  102. data/lib/method.rb +0 -4
  103. data/lib/object.rb +0 -5
  104. data/lib/proc.rb +0 -4
  105. data/lib/rubylog/builtins.rb +0 -193
  106. data/lib/rubylog/callable.rb +0 -20
  107. data/lib/rubylog/composite_term.rb +0 -38
  108. data/lib/rubylog/dsl/constants.rb +0 -15
  109. data/lib/rubylog/dsl/first_order_functors.rb +0 -9
  110. data/lib/rubylog/dsl/global_functors.rb +0 -3
  111. data/lib/rubylog/dsl/second_order_functors.rb +0 -8
  112. data/lib/rubylog/internal_helpers.rb +0 -16
  113. data/lib/rubylog/predicate.rb +0 -34
  114. data/lib/rubylog/proc_method_additions.rb +0 -69
  115. data/lib/rubylog/term.rb +0 -20
  116. data/lib/rubylog/unifiable.rb +0 -19
  117. data/lib/symbol.rb +0 -35
  118. data/script/inriasuite2spec +0 -0
  119. data/script/inriasuite2spec.pl +0 -22
  120. data/spec/rubylog/clause_spec.rb +0 -81
  121. data/spec/rubylog/variable_spec.rb +0 -25
  122. data/spec/rubylog_spec.rb +0 -914
data/Gemfile CHANGED
@@ -12,7 +12,7 @@ group :development do
12
12
  gem "cucumber", ">= 0"
13
13
  gem "bundler", "~> 1.0.0"
14
14
  gem "jeweler", "~> 1.8.3"
15
- gem "simplecov"
15
+ gem "simplecov", :require => false
16
16
  gem "reek", "~> 1.2.8"
17
17
  gem "roodi", "~> 2.1.0"
18
18
  end
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 an implementation of (part of) the Prolog language as a Ruby DSL. The DSL is inspired by {Jamis Buck}[http://weblog.jamisbuck.org/2006/10/28/prolog-in-ruby], and the implementation is based on {Yield Prolog}[http://yieldprolog.sourceforge.net/].
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
- == Using
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
- include Rubylog::DSL::Constants
13
- Symbol.rubylog_functor :likes, :drinks, :has
14
-
15
- A Rubylog clause can be created by sending the functor to the first argument, passing the other arguments:
16
- :john.likes :beer # likes(john,beer) in Prolog
17
-
18
- A variable is an undefined constant. Don't-care variables start with ANY...
19
- A, B, Cat # the same in Prolog
20
- ANY, ANYONE, ANYTHING # _ in Prolog
21
-
22
- Now you can start writing Rubylog predicates. Facts can be asserted with a bang:
23
- :john.likes! :beer # likes(john, beer). in Prolog
24
- :john.has! :beer
25
-
26
- Fact assertions return the first argument, so they can be chained:
27
- :john.likes!(:beer).has!(:beer)
28
-
29
- Rules can be asserted with +if+ and +unless+:
30
- X.drinks(Y).if X.has(Y).and X.likes(Y) # drinks(X,Y) :- has(X,Y), likes(X,Y). in Prolog
31
-
32
- Queries can be proved with a question mark or with +true?+:
33
- :john.drinks? :beer # => true
34
- (:john.drinks :beer).true? # => true
35
-
36
- Or solutions can be enumerated (clauses include Enumerable)
37
- (:john.drinks X).each {|x| p x} # outputs :beer
38
- (:john.drinks X).to_a # => [:beer]
39
-
40
- At most places you can mix native Ruby with Rubylog by using a proc instead of a clause. Blocks are automatically converted to proc objects:
41
- X.drinks(Y).if proc{|x,y| y.to_s =~ /^Z/ }
42
- X.drinks(Y).if {|x,y| y.to_s =~ /^Z/ } # the same
43
-
44
- X.drinks(Y).if X.likes(Y).and proc { Time.now.hour == 12 }
45
- X.drinks(Y).if X.likes(Y).and { Time.now.hour == 12 } # the same
46
-
47
- Variable values are passed to the proc, in the order of appearance.
48
-
49
- Nullary predicates are just symbols:
50
- :john.drinks(:beer).if :true.or :false
51
-
52
- For predicates requiring a simple value as an argument, you can pass a proc that returns that value
53
- X.drinks(Y).if Y.is proc{|x| $favorites[x] }
54
- X.drinks(Y).if Y.is {|x| $favorites[x] } # the same
55
-
56
-
57
- The Prolog built-in predicates and the Rubylog equivalents (see +Rubylog::Builtins+ for details):
58
-
59
- Prolog Rubylog
60
- ----------------------------------------
61
- true true
62
- fail fail
63
- , and, &
64
- ; or, |
65
- ! :cut
66
- -> then
67
- \+ is_false, fails, not, ~
68
- repeat repeat
69
- A=B A.is B
70
- X is Y*5 X.is{|y|y*5}
71
- proc{|x,y|y===x} or X.matches Y
72
- L=[H|T] L.splits_to(H,T)
73
- member(A,L) A.in L (L can be any enumerable)
74
- write(A) A._puts, A._print, A._p
75
- nl nl
76
- \+((A, \+ B)) A.all B
77
- (A,B)->true A.any B
78
- A.one B
79
- \+((A,B)) A.none B
80
- A,fail;true A.all
81
- A->true A.any
82
- A.one
83
- \+(A) A.none
84
-
85
-
86
-
87
-
88
- == Contributing to rubylog
89
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
90
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
91
- * Fork the project.
92
- * Start a feature/bugfix branch.
93
- * Commit and push until you are happy with your contribution.
94
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
95
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
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) 2012 Bernát Kalló. See LICENSE.txt for
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 :default => :spec
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
+ 1.0.0
data/bin/rubylog ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require "./lib/rubylog"
3
+
4
+ files = ARGV.empty? ? Dir['./logic/**/*_logic.rb'] : Dir[*ARGV].map{|f| File.expand_path f }
5
+ ARGV.clear
6
+
7
+
8
+ files.each do |x|
9
+ puts x
10
+
11
+ require x
12
+
13
+ puts
14
+ end
15
+
16
+
17
+
18
+
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
@@ -1,16 +1,17 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
1
2
  require 'rubylog'
2
3
 
3
- class << FactorialTheory = Rubylog::Theory.new!
4
+ FactorialTheory = theory do
5
+ subject Integer
6
+ functor :factorial
4
7
 
5
8
  0.factorial! 1
6
- N.factorial(K).if proc{|n|n>0}.and N1.is{|n|n-1}.and N1.factorial(K1).and K.is{|n,_,_,k1| n*k1}
7
-
8
- [0,1,2,7].each do |n|
9
- (n.factorial? K).solve{|k| puts "#{n} factorial is #{k}"}
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
- require "rubylog"
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
2
 
3
- Rubylog.use :variables, :implicit_predicates, String
3
+ require 'rubylog'
4
4
 
5
- A.write.if {|a| puts a; true}
6
- :hello.if "Hello, world!".write
7
5
 
8
- :hello.true?
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
 
@@ -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