rubylog 1.0.0 → 2.0pre1
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 +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
|