rubylog 1.0.0 → 2.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -12
- data/Gemfile.lock +22 -48
- data/README.rdoc +38 -38
- data/README.rdoc.orig +284 -0
- data/RELEASE_NOTES.rdoc +51 -0
- data/Rakefile +14 -18
- data/TODO.txt +0 -0
- data/VERSION +1 -1
- data/examples/a_plus_b.rb +6 -0
- data/examples/checkmate.rb +88 -0
- data/examples/combination.rb +17 -0
- data/examples/dcg.rb +3 -2
- data/examples/dcg2.rb +2 -2
- data/{logic → examples}/directory_structure_logic.rb +3 -5
- data/examples/dirlist.rb +4 -0
- data/examples/divisors.rb +6 -0
- data/examples/enumerators.rb +3 -3
- data/examples/factorial.rb +2 -3
- data/examples/file_search.rb +14 -0
- data/examples/hanoi.rb +4 -5
- data/examples/hello.rb +6 -4
- data/examples/mice.rb +92 -0
- data/examples/mice2.rb +19 -0
- data/examples/n_queens.rb +32 -0
- data/examples/object_oriented.rb +14 -0
- data/examples/palindrome_detection.rb +18 -0
- data/examples/parsing.rb +6 -4
- data/examples/permutation.rb +12 -0
- data/examples/prefix.rb +13 -0
- data/examples/primality_by_division.rb +22 -0
- data/examples/primitives.rb +10 -8
- data/examples/sieve_of_eratosthenes.rb +14 -0
- data/examples/string_interpolation.rb +4 -0
- data/examples/sudoku.rb +52 -0
- data/examples/tracing.rb +19 -0
- data/lib/rspec/rubylog.rb +29 -0
- data/lib/rubylog/assertable.rb +24 -0
- data/lib/rubylog/builtins/arithmetics.rb +63 -0
- data/lib/rubylog/builtins/assumption.rb +71 -0
- data/lib/rubylog/builtins/ensure.rb +13 -0
- data/lib/rubylog/builtins/file_system.rb +30 -8
- data/lib/rubylog/builtins/logic.rb +69 -38
- data/lib/rubylog/builtins/reflection.rb +35 -50
- data/lib/rubylog/builtins/term.rb +15 -17
- data/lib/rubylog/builtins.rb +11 -0
- data/lib/rubylog/clause.rb +19 -0
- data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
- data/lib/rubylog/context.rb +24 -0
- data/lib/rubylog/context_creation.rb +71 -0
- data/lib/rubylog/context_modules/checks.rb +35 -0
- data/lib/rubylog/context_modules/demonstration.rb +16 -0
- data/lib/rubylog/context_modules/predicates.rb +86 -0
- data/lib/rubylog/context_modules/primitives.rb +18 -0
- data/lib/rubylog/context_modules/thats.rb +13 -0
- data/lib/rubylog/default_context.rb +9 -0
- data/lib/rubylog/dsl/array_splat.rb +11 -3
- data/lib/rubylog/dsl/primitives.rb +24 -12
- data/lib/rubylog/dsl/thats.rb +6 -0
- data/lib/rubylog/dsl/variables.rb +56 -21
- data/lib/rubylog/errors.rb +26 -15
- data/lib/rubylog/mixins/array.rb +95 -62
- data/lib/rubylog/mixins/kernel.rb +3 -2
- data/lib/rubylog/mixins/method.rb +0 -1
- data/lib/rubylog/mixins/object.rb +2 -1
- data/lib/rubylog/mixins/proc.rb +9 -12
- data/lib/rubylog/mixins/string.rb +15 -23
- data/lib/rubylog/mixins/symbol.rb +7 -24
- data/lib/rubylog/nullary_predicates.rb +3 -0
- data/lib/rubylog/predicate.rb +53 -0
- data/lib/rubylog/primitive.rb +15 -0
- data/lib/rubylog/procedure.rb +42 -0
- data/lib/rubylog/rule.rb +24 -0
- data/lib/rubylog/structure.rb +19 -38
- data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
- data/lib/rubylog/tracing.rb +75 -0
- data/lib/rubylog/variable.rb +31 -12
- data/lib/rubylog.rb +36 -32
- data/rubylog.gemspec +92 -84
- data/spec/inriasuite_spec.rb +906 -9
- data/spec/integration/custom_classes_spec.rb +61 -0
- data/spec/integration/dsl_spec.rb +38 -0
- data/spec/integration/recursion_spec.rb +14 -0
- data/spec/integration/theory_as_module_spec.rb +20 -0
- data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
- data/spec/rspec/rubylog_spec.rb +75 -0
- data/spec/rubylog/assertable_spec.rb +111 -0
- data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
- data/spec/rubylog/builtins/assumption_spec.rb +70 -0
- data/spec/rubylog/builtins/ensure_spec.rb +8 -0
- data/spec/rubylog/builtins/file_system_spec.rb +40 -0
- data/spec/rubylog/builtins/logic_spec.rb +340 -0
- data/spec/rubylog/builtins/reflection_spec.rb +43 -0
- data/spec/rubylog/builtins/term_spec.rb +85 -0
- data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
- data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
- data/spec/rubylog/context_modules/thats_spec.rb +94 -0
- data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
- data/spec/rubylog/dsl/primitives_spec.rb +43 -0
- data/spec/rubylog/errors_spec.rb +18 -0
- data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
- data/spec/rubylog/mixins/array_spec.rb +80 -0
- data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
- data/spec/rubylog/mixins/proc_spec.rb +59 -0
- data/spec/rubylog/mixins/string_spec.rb +48 -0
- data/spec/rubylog/mixins/symbol_spec.rb +9 -0
- data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
- data/spec/rubylog/term_spec.rb +7 -0
- data/spec/rubylog/tracing_spec.input +27 -0
- data/spec/rubylog/tracing_spec.rb +44 -0
- data/spec/rubylog/variable_spec.rb +279 -0
- data/spec/spec_helper.rb +1 -0
- data/vimrc +11 -0
- metadata +103 -123
- data/README.hu.rb +0 -58
- data/bin/rubylog +0 -18
- data/examples/theory.rb +0 -32
- data/lib/rubylog/builtins/default.rb +0 -10
- data/lib/rubylog/dsl.rb +0 -70
- data/lib/rubylog/interfaces/assertable.rb +0 -16
- data/lib/rubylog/interfaces/callable.rb +0 -18
- data/lib/rubylog/interfaces/predicate.rb +0 -8
- data/lib/rubylog/interfaces/procedure.rb +0 -60
- data/lib/rubylog/mixins/class.rb +0 -11
- data/lib/rubylog/simple_procedure.rb +0 -8
- data/lib/rubylog/theory.rb +0 -422
- data/logic/builtins/file_system_logic.rb +0 -23
- data/logic/builtins/reflection_logic.rb +0 -40
- data/logic/dereference_logic.rb +0 -23
- data/logic/dsl_logic.rb +0 -29
- data/logic/errors_logic.rb +0 -9
- data/logic/guard_logic.rb +0 -115
- data/logic/list_logic.rb +0 -55
- data/logic/map_logic.rb +0 -15
- data/logic/multitheory.rb +0 -23
- data/logic/recursion_logic.rb +0 -12
- data/logic/string_logic.rb +0 -41
- data/logic/thats_logic.rb +0 -51
- data/logic/variable_logic.rb +0 -24
- data/spec/bartak_guide_spec.rb +0 -86
- data/spec/builtins/all_spec.rb +0 -99
- data/spec/builtins/and_spec.rb +0 -22
- data/spec/builtins/array_spec.rb +0 -16
- data/spec/builtins/branch_or_spec.rb +0 -27
- data/spec/builtins/cut_spec.rb +0 -44
- data/spec/builtins/fail_spec.rb +0 -5
- data/spec/builtins/false_spec.rb +0 -5
- data/spec/builtins/in_spec.rb +0 -38
- data/spec/builtins/is_false_spec.rb +0 -12
- data/spec/builtins/is_spec.rb +0 -26
- data/spec/builtins/matches_spec.rb +0 -23
- data/spec/builtins/or_spec.rb +0 -22
- data/spec/builtins/splits_to.rb +0 -18
- data/spec/builtins/then_spec.rb +0 -27
- data/spec/builtins/true_spec.rb +0 -5
- data/spec/compilation_spec.rb +0 -61
- data/spec/custom_classes_spec.rb +0 -43
- data/spec/dereference.rb +0 -10
- data/spec/queries_spec.rb +0 -150
- data/spec/recursion_spec.rb +0 -18
- data/spec/ruby_code_spec.rb +0 -52
- data/spec/rules_spec.rb +0 -97
- data/spec/theory_spec.rb +0 -29
- data/spec/variable_spec.rb +0 -26
data/Gemfile
CHANGED
@@ -1,18 +1,9 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
5
2
|
|
6
|
-
# Add dependencies to develop your gem here.
|
7
|
-
# Include everything needed to run rake, tests, features, etc.
|
8
3
|
group :development do
|
9
|
-
gem "rspec", "
|
4
|
+
gem "rspec", ">= 2.8.0", " < 3"
|
10
5
|
gem "yard", "~> 0.7"
|
11
|
-
gem "
|
12
|
-
gem "
|
13
|
-
gem "bundler", "~> 1.0.0"
|
14
|
-
gem "jeweler", "~> 1.8.3"
|
6
|
+
gem "bundler", ">= 1.0.0"
|
7
|
+
gem "jeweler", ">= 1.8.3"
|
15
8
|
gem "simplecov", :require => false
|
16
|
-
gem "reek", "~> 1.2.8"
|
17
|
-
gem "roodi", "~> 2.1.0"
|
18
9
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,64 +1,38 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
|
5
|
-
cucumber (1.1.4)
|
6
|
-
builder (>= 2.1.2)
|
7
|
-
diff-lcs (>= 1.1.2)
|
8
|
-
gherkin (~> 2.7.1)
|
9
|
-
json (>= 1.4.6)
|
10
|
-
term-ansicolor (>= 1.0.6)
|
11
|
-
diff-lcs (1.1.3)
|
12
|
-
gherkin (2.7.6)
|
13
|
-
json (>= 1.4.6)
|
4
|
+
diff-lcs (1.2.4)
|
14
5
|
git (1.2.5)
|
15
|
-
jeweler (1.8.
|
6
|
+
jeweler (1.8.4)
|
16
7
|
bundler (~> 1.0)
|
17
8
|
git (>= 1.2.5)
|
18
9
|
rake
|
19
10
|
rdoc
|
20
|
-
json (1.
|
21
|
-
multi_json (1.
|
22
|
-
rake (0.
|
23
|
-
rdoc (
|
11
|
+
json (1.7.7)
|
12
|
+
multi_json (1.7.2)
|
13
|
+
rake (10.0.4)
|
14
|
+
rdoc (4.0.1)
|
24
15
|
json (~> 1.4)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
rspec-mocks (2.8.0)
|
39
|
-
ruby2ruby (1.3.1)
|
40
|
-
ruby_parser (~> 2.0)
|
41
|
-
sexp_processor (~> 3.0)
|
42
|
-
ruby_parser (2.3.1)
|
43
|
-
sexp_processor (~> 3.0)
|
44
|
-
sexp_processor (3.0.10)
|
45
|
-
simplecov (0.5.4)
|
46
|
-
multi_json (~> 1.0.3)
|
47
|
-
simplecov-html (~> 0.5.3)
|
48
|
-
simplecov-html (0.5.3)
|
49
|
-
term-ansicolor (1.0.7)
|
50
|
-
yard (0.7.5)
|
16
|
+
rspec (2.13.0)
|
17
|
+
rspec-core (~> 2.13.0)
|
18
|
+
rspec-expectations (~> 2.13.0)
|
19
|
+
rspec-mocks (~> 2.13.0)
|
20
|
+
rspec-core (2.13.1)
|
21
|
+
rspec-expectations (2.13.0)
|
22
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
23
|
+
rspec-mocks (2.13.1)
|
24
|
+
simplecov (0.7.1)
|
25
|
+
multi_json (~> 1.0)
|
26
|
+
simplecov-html (~> 0.7.1)
|
27
|
+
simplecov-html (0.7.1)
|
28
|
+
yard (0.8.6.1)
|
51
29
|
|
52
30
|
PLATFORMS
|
53
31
|
ruby
|
54
32
|
|
55
33
|
DEPENDENCIES
|
56
|
-
bundler (
|
57
|
-
|
58
|
-
|
59
|
-
rdoc (~> 3.12)
|
60
|
-
reek (~> 1.2.8)
|
61
|
-
roodi (~> 2.1.0)
|
62
|
-
rspec (~> 2.8.0)
|
34
|
+
bundler (>= 1.0.0)
|
35
|
+
jeweler (>= 1.8.3)
|
36
|
+
rspec (>= 2.8.0, < 3)
|
63
37
|
simplecov
|
64
38
|
yard (~> 0.7)
|
data/README.rdoc
CHANGED
@@ -5,6 +5,8 @@ Buck}[http://weblog.jamisbuck.org/2006/10/28/prolog-in-ruby], and the
|
|
5
5
|
implementation is based on {Yield Prolog}[http://yieldprolog.sourceforge.net/],
|
6
6
|
with lots of sintactic and semantic additions.
|
7
7
|
|
8
|
+
See the {wiki}[https://github.com/cie/rubylog/wiki] for online documentation.
|
9
|
+
|
8
10
|
== Getting started
|
9
11
|
|
10
12
|
First, install the gem
|
@@ -13,19 +15,14 @@ First, install the gem
|
|
13
15
|
|
14
16
|
or, if you use +bundler+, add this line to your +Gemfile+:
|
15
17
|
|
16
|
-
gem 'rubylog', '~>
|
18
|
+
gem 'rubylog', '~>2.0pre1'
|
17
19
|
|
18
20
|
|
19
21
|
|
20
|
-
First, you
|
22
|
+
First, you need a Rubylog context. The simplest you can do is to extend Rubylog::Context into the main object.
|
21
23
|
|
22
24
|
require 'rubylog'
|
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.
|
25
|
+
extend Rubylog::Context
|
29
26
|
|
30
27
|
|
31
28
|
=== Data types
|
@@ -40,13 +37,6 @@ Rubylog variables are (undefined) constant names:
|
|
40
37
|
A variables whose name starts with +ANY...+ (case-insensitive) is a don't-care
|
41
38
|
variable (like +_+ in Prolog).
|
42
39
|
|
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
40
|
Lists are just Ruby arrays:
|
51
41
|
|
52
42
|
[1, 2, 3]
|
@@ -55,28 +45,36 @@ They can have splats:
|
|
55
45
|
|
56
46
|
[1, 2, *T]
|
57
47
|
|
58
|
-
Which would be
|
48
|
+
Which would be <tt>[1,2|T]</tt> in Prolog, however, in Rubylog, splats are not limited
|
59
49
|
to the end.
|
60
50
|
|
61
51
|
=== Predicates
|
52
|
+
As in prolog, predicates are the buinding blocks of your program. However, the arguments are in a different order than they are in prolog:
|
53
|
+
|
54
|
+
predicate_for String, ".likes()"
|
55
|
+
'John'.likes!('beer')
|
56
|
+
|
57
|
+
which would be <tt>likes('John','beer').</tt> in prolog. In Rubylog, predicates must be declared. The string indicating the predicate syntax is <tt>".likes()"</tt>. The format is <tt>:asdf .asdf .asdf() .asdf(,) .asdf(,,)</tt> for predicates with 0,1,2,3,4 arguments.
|
62
58
|
|
63
59
|
You can assert a rule with the +if+ method:
|
64
60
|
|
61
|
+
predicate_for String, ".drinks() .has()"
|
65
62
|
X.drinks(Y).if X.has(Y).and X.likes(Y)
|
66
63
|
|
67
64
|
This would be +drinks(X,Y) :- has(X,Y), likes(X,Y)+ in Prolog.
|
68
65
|
|
69
|
-
You can assert facts with
|
66
|
+
You can assert facts with <tt>if(:true)</tt>, or, as a shorthand you can use the bang
|
70
67
|
syntax:
|
71
68
|
|
72
69
|
'John'.likes! 'milk'
|
73
70
|
|
74
|
-
Bang assertions return their first argument (which is
|
71
|
+
Bang assertions return their first argument (which is <tt>'John'</tt> in this case), so they can be chained:
|
75
72
|
|
76
73
|
'John'.likes!('beer').has!('beer')
|
77
74
|
|
78
75
|
You can also use +unless+:
|
79
76
|
|
77
|
+
predicate_for String, ".good .bad"
|
80
78
|
A.good.unless A.bad
|
81
79
|
|
82
80
|
Nullary predicates are symbols, similar to Prolog:
|
@@ -93,17 +91,22 @@ Some built-in predicates and their Prolog equivalents:
|
|
93
91
|
------- ------
|
94
92
|
:true true
|
95
93
|
:fail fail
|
96
|
-
.and
|
97
|
-
.or
|
94
|
+
.and() ,
|
95
|
+
.or() ;
|
98
96
|
:false \+
|
99
|
-
.is
|
100
|
-
.is_not
|
101
|
-
.in
|
97
|
+
.is() =
|
98
|
+
.is_not() =/=
|
99
|
+
.in() member
|
102
100
|
:cut! !
|
103
101
|
|
104
102
|
There are some new ones:
|
105
103
|
|
106
|
-
|
104
|
+
not_in, all, any, one, none, iff
|
105
|
+
|
106
|
+
You can see reference of these in <tt>lib/rubylog/builtins/logic.rb</tt> and <tt>lib/rubylog/builtins/term.rb</tt>
|
107
|
+
|
108
|
+
|
109
|
+
See the documentation in <tt>lib/rubylog/builtins/</tt>
|
107
110
|
|
108
111
|
=== Unification
|
109
112
|
|
@@ -180,23 +183,24 @@ variables are substituted with their respecitve value (or +nil+ if they are not
|
|
180
183
|
bound).
|
181
184
|
|
182
185
|
All built-in rubylog predicates are clean logical programming predicates witout
|
183
|
-
a side-effect. If you want some side-
|
186
|
+
a side-effect. If you want some side-effects, you always go into native mode.
|
184
187
|
|
185
188
|
=== Rubylog as a test suite
|
186
189
|
|
187
190
|
You can write simple tests using the +check+ method:
|
188
191
|
|
189
192
|
theory do
|
190
|
-
check :true
|
193
|
+
check :true.or :false
|
194
|
+
check A.is(3).and A.in [1,2,3]
|
191
195
|
check { 5+5 == 10 }
|
192
196
|
end
|
193
197
|
|
194
|
-
You sould put this file in
|
198
|
+
You sould put this file in <tt>"./logic/something\_logic.rb"</tt>. Then you can run it
|
195
199
|
with
|
196
200
|
|
197
201
|
rubylog logic/something_logic.rb
|
198
202
|
|
199
|
-
Or you can run all files in
|
203
|
+
Or you can run all files in <tt>logic/**/*\_logic.rb</tt> with
|
200
204
|
|
201
205
|
rubylog
|
202
206
|
|
@@ -240,18 +244,14 @@ You can make some metaprogramming with Rubylog
|
|
240
244
|
== Contributing
|
241
245
|
|
242
246
|
=== 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
|
|
247
|
-
|
248
|
+
* Post your own examples to the {wiki}[https://github.com/cie/rubylog/wiki/Examples].
|
249
|
+
* Improve others' examples.
|
250
|
+
* If you have a suggestion for the language, submit an issue.
|
251
|
+
|
252
|
+
=== Reporting bugs or requesting features
|
253
|
+
|
248
254
|
* 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.
|
255
255
|
|
256
256
|
== Copyright
|
257
257
|
|
data/README.rdoc.orig
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
= Rubylog - Prolog interpreter for ruby
|
2
|
+
|
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
|
+
See the {wiki}[https://github.com/cie/rubylog/wiki] for online documentation.
|
9
|
+
|
10
|
+
== Getting started
|
11
|
+
|
12
|
+
First, install the gem
|
13
|
+
|
14
|
+
$ gem install rubylog
|
15
|
+
|
16
|
+
or, if you use +bundler+, add this line to your +Gemfile+:
|
17
|
+
|
18
|
+
gem 'rubylog', '~>2.0pre1'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
First, you need a Rubylog context. The simplest you can do is to extend Rubylog::Context into the main object.
|
23
|
+
|
24
|
+
require 'rubylog'
|
25
|
+
extend Rubylog::Context
|
26
|
+
|
27
|
+
|
28
|
+
=== Data types
|
29
|
+
|
30
|
+
Rubylog is similar to Prolog, but there are quite a few differences. In Rubylog,
|
31
|
+
you can use any Ruby object as data.
|
32
|
+
|
33
|
+
Rubylog variables are (undefined) constant names:
|
34
|
+
|
35
|
+
A, B, ANYTHING
|
36
|
+
|
37
|
+
A variables whose name starts with +ANY...+ (case-insensitive) is a don't-care
|
38
|
+
variable (like +_+ in Prolog).
|
39
|
+
|
40
|
+
<<<<<<< HEAD
|
41
|
+
Structures are in a different order than they are in prolog:
|
42
|
+
|
43
|
+
functor_for String, :likes
|
44
|
+
'John'.likes('beer')
|
45
|
+
|
46
|
+
which would be <tt>likes('John','beer')</tt> in prolog.
|
47
|
+
|
48
|
+
=======
|
49
|
+
>>>>>>> develop
|
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 <tt>[1,2|T]</tt> in Prolog, however, in Rubylog, splats are not limited
|
59
|
+
to the end.
|
60
|
+
|
61
|
+
=== Predicates
|
62
|
+
As in prolog, predicates are the buinding blocks of your program. However, the arguments are in a different order than they are in prolog:
|
63
|
+
|
64
|
+
predicate_for String, ".likes()"
|
65
|
+
'John'.likes!('beer')
|
66
|
+
|
67
|
+
which would be <tt>likes('John','beer').</tt> in prolog. In Rubylog, predicates must be declared. The string indicating the predicate syntax is <tt>".likes()"</tt>. The format is <tt>:asdf .asdf .asdf() .asdf(,) .asdf(,,)</tt> for predicates with 0,1,2,3,4 arguments.
|
68
|
+
|
69
|
+
You can assert a rule with the +if+ method:
|
70
|
+
|
71
|
+
predicate_for String, ".drinks() .has()"
|
72
|
+
X.drinks(Y).if X.has(Y).and X.likes(Y)
|
73
|
+
|
74
|
+
This would be +drinks(X,Y) :- has(X,Y), likes(X,Y)+ in Prolog.
|
75
|
+
|
76
|
+
You can assert facts with <tt>if(:true)</tt>, or, as a shorthand you can use the bang
|
77
|
+
syntax:
|
78
|
+
|
79
|
+
'John'.likes! 'milk'
|
80
|
+
|
81
|
+
Bang assertions return their first argument (which is <tt>'John'</tt> in this case), so they can be chained:
|
82
|
+
|
83
|
+
'John'.likes!('beer').has!('beer')
|
84
|
+
|
85
|
+
You can also use +unless+:
|
86
|
+
|
87
|
+
predicate_for String, ".good .bad"
|
88
|
+
A.good.unless A.bad
|
89
|
+
|
90
|
+
Nullary predicates are symbols, similar to Prolog:
|
91
|
+
|
92
|
+
'John'.drinks('beer').if :false.and(:cut!).or(:true)
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
=== Built-in predicates
|
97
|
+
|
98
|
+
Some built-in predicates and their Prolog equivalents:
|
99
|
+
|
100
|
+
<<<<<<< HEAD
|
101
|
+
Prolog Rubylog
|
102
|
+
------ -------
|
103
|
+
true/0 :true
|
104
|
+
fail/0 :fail
|
105
|
+
','/2 .and()
|
106
|
+
';'/2 .or()
|
107
|
+
'\+'/1 .false
|
108
|
+
'='/2 .is()
|
109
|
+
'=/='/2 .is_not()
|
110
|
+
member/2 .in()
|
111
|
+
'!'/0 :cut!
|
112
|
+
=======
|
113
|
+
Rubylog Prolog
|
114
|
+
------- ------
|
115
|
+
:true true
|
116
|
+
:fail fail
|
117
|
+
.and() ,
|
118
|
+
.or() ;
|
119
|
+
:false \+
|
120
|
+
.is() =
|
121
|
+
.is_not() =/=
|
122
|
+
.in() member
|
123
|
+
:cut! !
|
124
|
+
>>>>>>> develop
|
125
|
+
|
126
|
+
There are some new ones:
|
127
|
+
|
128
|
+
not_in, all, any, one, none, iff
|
129
|
+
|
130
|
+
You can see reference of these in <tt>lib/rubylog/builtins/logic.rb</tt> and <tt>lib/rubylog/builtins/term.rb</tt>
|
131
|
+
|
132
|
+
|
133
|
+
See the documentation in <tt>lib/rubylog/builtins/</tt>
|
134
|
+
|
135
|
+
=== Unification
|
136
|
+
|
137
|
+
In Rubylog, unification works quite the same in Prolog, with the +is+ functor.
|
138
|
+
|
139
|
+
A.is(B)
|
140
|
+
|
141
|
+
Using arrays, you can benefit the splats:
|
142
|
+
|
143
|
+
[1,2,3,4].is([A,B,*T]) # [1,2,3,4] = [A,B|T] in prolog
|
144
|
+
[1,2,3,4].is([*H,*T]) # append(H, T, [1,2,3,4]) in prolog
|
145
|
+
|
146
|
+
The +in+ predicate unifies the first argument with any member of the collection:
|
147
|
+
|
148
|
+
4.in([1,2,3,4])
|
149
|
+
|
150
|
+
You can use guards:
|
151
|
+
|
152
|
+
A[String].in(["asdf",5,nil]).each { p A } # outputs "asdf"
|
153
|
+
A[/x/].in(["asdf","xyz"]).each { p A } # outputs "xyz"
|
154
|
+
A[thats < 5].in([4,5,6]).each { p A } # outputs 4
|
155
|
+
|
156
|
+
=== Moving between Ruby and Rubylog
|
157
|
+
==== Running a query
|
158
|
+
|
159
|
+
If you want to run a query, you have many different syntaxes:
|
160
|
+
|
161
|
+
prove ('John'.drinks 'beer') # => true
|
162
|
+
true? ('John'.drinks 'beer') # => true
|
163
|
+
('John'.drinks 'beer').true? # => true
|
164
|
+
'John'.drinks? 'beer' # => true
|
165
|
+
|
166
|
+
==== Enumerations
|
167
|
+
|
168
|
+
+Structure+ implements +Enumerable+, and yields the solutions. Within the
|
169
|
+
enumeration block, you can access the values of your variables.
|
170
|
+
|
171
|
+
'John'.drinks! 'beer'
|
172
|
+
('John'.drinks X).each {p X} # outputs 'beer'
|
173
|
+
('John'.drinks X).map{X} # => ['beer']
|
174
|
+
('John'.drinks X).count # => 1
|
175
|
+
|
176
|
+
==== Procs as predicates
|
177
|
+
|
178
|
+
You can invoke Ruby codes in Rubylog rules with a proc:
|
179
|
+
|
180
|
+
'John'.likes(Y).if proc{ Y =~ /ale/ }
|
181
|
+
|
182
|
+
or in most cases you can use just a block:
|
183
|
+
|
184
|
+
'John'.likes(Y).if { Y =~ /ale/ }
|
185
|
+
|
186
|
+
The predicate succeeds if the block returns a true value.
|
187
|
+
|
188
|
+
==== Procs as functions
|
189
|
+
|
190
|
+
+is+ and +in+ can take a proc or block argument, which they execute and take its return value:
|
191
|
+
|
192
|
+
X.good.if X.is { 'BEER'.downcase }
|
193
|
+
X.good.if X.in { get_good_drinks() }
|
194
|
+
|
195
|
+
==== The two modes of Rubylog
|
196
|
+
|
197
|
+
Rubylog has two modes, DSL and native. DSL code is executed only once
|
198
|
+
at compile time, and is used for describing the Rubylog program. Native code is
|
199
|
+
executed runtime. Any block passed to Rubylog structures native code.
|
200
|
+
|
201
|
+
('John'.drinks X).and { X != 'beer'}.each { p X }
|
202
|
+
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ dsl mode
|
203
|
+
^^^^^^^^^^^^ ^^^^^ native mode
|
204
|
+
|
205
|
+
In dsl mode, variables are +Rubylog::Variable+ objects. In native mode,
|
206
|
+
variables are substituted with their respecitve value (or +nil+ if they are not
|
207
|
+
bound).
|
208
|
+
|
209
|
+
All built-in rubylog predicates are clean logical programming predicates witout
|
210
|
+
a side-effect. If you want some side-effects, you always go into native mode.
|
211
|
+
|
212
|
+
=== Rubylog as a test suite
|
213
|
+
|
214
|
+
You can write simple tests using the +check+ method:
|
215
|
+
|
216
|
+
theory do
|
217
|
+
check :true.or :false
|
218
|
+
check A.is(3).and A.in [1,2,3]
|
219
|
+
check { 5+5 == 10 }
|
220
|
+
end
|
221
|
+
|
222
|
+
You sould put this file in <tt>"./logic/something\_logic.rb"</tt>. Then you can run it
|
223
|
+
with
|
224
|
+
|
225
|
+
rubylog logic/something_logic.rb
|
226
|
+
|
227
|
+
Or you can run all files in <tt>logic/**/*\_logic.rb</tt> with
|
228
|
+
|
229
|
+
rubylog
|
230
|
+
|
231
|
+
=== Other built-in libraries
|
232
|
+
|
233
|
+
==== File system
|
234
|
+
|
235
|
+
You can make some queries on the file system:
|
236
|
+
|
237
|
+
require "rubylog/builtins/file_system"
|
238
|
+
|
239
|
+
theory do
|
240
|
+
check "README".filename_in "."
|
241
|
+
|
242
|
+
X.dirname_in(".").each { puts X }
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
==== Reflection
|
247
|
+
|
248
|
+
You can make some metaprogramming with Rubylog
|
249
|
+
|
250
|
+
|
251
|
+
require "rubylog/builtins/reflection"
|
252
|
+
|
253
|
+
theory do
|
254
|
+
functor_for String, :likes
|
255
|
+
|
256
|
+
check "John".likes("Jane").structure(:likes, ["John", "Jane"])
|
257
|
+
|
258
|
+
"John".likes(X).if X.likes("John")
|
259
|
+
"Jane".likes!("John")
|
260
|
+
check "John".likes("Jane").follows_from "Jane".likes("John")
|
261
|
+
|
262
|
+
"John".likes!("milk")
|
263
|
+
check "John".likes("milk").fact
|
264
|
+
check "John".likes("beer").fact.false
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
== Contributing
|
269
|
+
|
270
|
+
=== To the language
|
271
|
+
|
272
|
+
* Post your own examples to the {wiki}[https://github.com/cie/rubylog/wiki/Examples].
|
273
|
+
* Improve others' examples.
|
274
|
+
* If you have a suggestion for the language, submit an issue.
|
275
|
+
|
276
|
+
=== Reporting bugs or requesting features
|
277
|
+
|
278
|
+
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
|
279
|
+
|
280
|
+
== Copyright
|
281
|
+
|
282
|
+
Copyright (c) 2013 Bernát Kalló. See LICENSE.txt for
|
283
|
+
further details.
|
284
|
+
|
data/RELEASE_NOTES.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
== Version 2.1 (planned)
|
2
|
+
* New features
|
3
|
+
* solve without a block returns an enumerator
|
4
|
+
* warning for singleton variables
|
5
|
+
* predicate for checking bound/unbound variables
|
6
|
+
|
7
|
+
== Version 2.0.0 (to be released)
|
8
|
+
* Backwards incompatibilities
|
9
|
+
* <tt>Rubylog.theory</tt> is removed. Use <tt>Kernel#Rubylog</tt>.
|
10
|
+
* <tt>file\_in</tt> includes directories and yields relative paths.
|
11
|
+
<tt>dir\_in</tt> also yields relative paths.
|
12
|
+
* <tt>trace</tt> has became <tt>Rubylog.trace</tt>. If you use
|
13
|
+
<tt>Kernel#Rubylog</tt>, it does not matter.
|
14
|
+
* <tt>Theory</tt> has changed to <tt>Context</tt> and it became a module.
|
15
|
+
* No more inclusion of theories (contexts).
|
16
|
+
* Predicates do not have reference in the theory (context), they are only referenced from the
|
17
|
+
subject class in closures of the functor methods.
|
18
|
+
* Unification uses <tt>eql?</tt> instead of <tt>==</tt>. This means
|
19
|
+
<tt>5.0.is\_not(5)</tt>
|
20
|
+
* <tt>Theory#eval</tt> removed. Use <tt>Context#instance\_eval</tt>.
|
21
|
+
* Removed <tt>functor</tt>, use <tt>predicate</tt> and <tt>predicate\_for</tt>
|
22
|
+
instead. The latter ones have a different syntax for indicating predicates, eg.
|
23
|
+
<tt>".and() .false :true"</tt> or <tt>"L.splits\_to(H,T)"</tt>
|
24
|
+
* <tt>Structure</tt> is bound to the predicate it represents. The first argument of <tt>Structure.new</tt> is the predicate. <tt>S.structure(Predicate,Functor,Args)</tt> now has 4 arguments.
|
25
|
+
* <tt>current\_theory</tt> is removed.
|
26
|
+
* No more real prefix functors, n-ary prefix functors are n\+1-ary functors with the context object as the first argument. Use <tt>predicate\_for Rubylog::Context, "..."</tt>.
|
27
|
+
* <tt>Rubylog::DefaultBuiltins</tt> is replaced by <tt>Rubylog</tt>
|
28
|
+
* <tt>Theory#prove</tt> was removed. Use <tt>Context#true?</tt>
|
29
|
+
* <tt>Rubylog::Callable<tt> renamed to <tt>Rubylog::Clause</tt>
|
30
|
+
* <tt>discontiguous</tt> is removed. No more discontiguity checks.
|
31
|
+
* <tt>implicit</tt> is removed. No implicit mode anymore.
|
32
|
+
* <tt>Theory#clear</tt> is replaced by <tt>Context#initialize\_context</tt>.
|
33
|
+
However, currently it only clears <tt>default\_subject</tt>.
|
34
|
+
* <tt>CompositeTerm</tt> is renamed to <tt>CompoundTerm</tt>.
|
35
|
+
* <tt>rublog\_compile\_variables</tt> is renamed to
|
36
|
+
<tt>rubylog\_match\_variables</tt>, <tt>variable\_hashes</tt> is removed.
|
37
|
+
* <tt>rubylog\_variables\_hash</tt> removed
|
38
|
+
* Features
|
39
|
+
* Rspec integration
|
40
|
+
* +include+ or +extend+ <tt>Rubylog::Context</tt> into any class or object
|
41
|
+
* thats\_not
|
42
|
+
* Comments in indicators
|
43
|
+
* New tracer
|
44
|
+
* added <tt>every</tt>
|
45
|
+
* all builtins are available by default
|
46
|
+
* Bug fixes
|
47
|
+
|
48
|
+
|
49
|
+
== Version 1.0.0
|
50
|
+
== Version 0.0.1
|
51
|
+
== Version 0.0.0
|
data/Rakefile
CHANGED
@@ -11,14 +11,16 @@ rescue Bundler::BundlerError => e
|
|
11
11
|
end
|
12
12
|
require 'rake'
|
13
13
|
|
14
|
+
# Jeweler - gem manager
|
14
15
|
require 'jeweler'
|
15
16
|
Jeweler::Tasks.new do |gem|
|
16
17
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
18
|
gem.name = "rubylog"
|
19
|
+
gem.version = File.open("VERSION"){|f|f.readline.strip}
|
18
20
|
gem.homepage = "https://github.com/cie/rubylog"
|
19
21
|
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{
|
21
|
-
gem.description = %Q{Rubylog is
|
22
|
+
gem.summary = %Q{A Prolog-like DSL}
|
23
|
+
gem.description = %Q{Rubylog is a Prolog-like DSL for Ruby.}
|
22
24
|
gem.email = "kallo.bernat@gmail.com"
|
23
25
|
gem.authors = ["Bernát Kalló"]
|
24
26
|
gem.executables = Dir["bin/*"].map{|x|File.basename x}
|
@@ -26,33 +28,27 @@ Jeweler::Tasks.new do |gem|
|
|
26
28
|
end
|
27
29
|
Jeweler::RubygemsDotOrgTasks.new
|
28
30
|
|
31
|
+
# RSpec - for tests
|
29
32
|
require 'rspec/core'
|
30
33
|
require 'rspec/core/rake_task'
|
31
34
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
32
35
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
33
36
|
end
|
34
37
|
|
35
|
-
require '
|
36
|
-
|
38
|
+
require 'yard'
|
39
|
+
YARD::Rake::YardocTask.new
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
t.fail_on_error = true
|
41
|
-
t.verbose = false
|
42
|
-
t.source_files = 'lib/**/*.rb'
|
41
|
+
file "doc/models.dot" do |f|
|
42
|
+
sh "yard graph > #{f.name}"
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
RoodiTask.new do |t|
|
48
|
-
t.verbose = false
|
45
|
+
rule ".svg" => ".dot" do |f|
|
46
|
+
sh "fdp #{f.source} -Tsvg > #{f.name}"
|
49
47
|
end
|
50
48
|
|
51
|
-
task :
|
52
|
-
|
49
|
+
task :yardserver do
|
50
|
+
sh "yard server --reload"
|
53
51
|
end
|
54
52
|
|
55
|
-
task :default => :logic
|
56
53
|
|
57
|
-
|
58
|
-
YARD::Rake::YardocTask.new
|
54
|
+
|
data/TODO.txt
ADDED
File without changes
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0pre1
|