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/lib/rubylog.rb
CHANGED
@@ -1,39 +1,47 @@
|
|
1
|
-
# rubylog
|
1
|
+
# rubylog -- Prolog workalike for Ruby
|
2
2
|
# github.com/cie/rubylog
|
3
|
+
module Rubylog
|
4
|
+
end
|
3
5
|
|
4
6
|
# rtl
|
5
7
|
require 'set'
|
6
8
|
|
9
|
+
dir = File.dirname(__FILE__) + "/"
|
10
|
+
|
7
11
|
# interfaces
|
8
|
-
require 'rubylog/term
|
9
|
-
require 'rubylog/callable
|
10
|
-
require 'rubylog/
|
11
|
-
require 'rubylog/composite_term
|
12
|
+
require dir+'rubylog/interfaces/term'
|
13
|
+
require dir+'rubylog/interfaces/callable'
|
14
|
+
require dir+'rubylog/interfaces/assertable'
|
15
|
+
require dir+'rubylog/interfaces/composite_term'
|
16
|
+
require dir+'rubylog/interfaces/predicate'
|
17
|
+
require dir+'rubylog/interfaces/procedure'
|
12
18
|
|
13
19
|
# helpers
|
14
|
-
require 'rubylog/dsl
|
15
|
-
require 'rubylog/dsl/
|
16
|
-
require 'rubylog/dsl/
|
17
|
-
require 'rubylog/dsl/
|
18
|
-
require 'rubylog/dsl/
|
19
|
-
require 'rubylog/
|
20
|
-
require 'rubylog/internal_helpers.rb'
|
20
|
+
require dir+'rubylog/dsl'
|
21
|
+
require dir+'rubylog/dsl/variables'
|
22
|
+
require dir+'rubylog/dsl/primitives'
|
23
|
+
require dir+'rubylog/dsl/array_splat'
|
24
|
+
require dir+'rubylog/dsl/thats'
|
25
|
+
require dir+'rubylog/errors'
|
21
26
|
|
22
27
|
# classes
|
23
|
-
require 'rubylog/
|
24
|
-
require 'rubylog/
|
25
|
-
require 'rubylog/
|
26
|
-
require 'rubylog/
|
28
|
+
require dir+'rubylog/theory'
|
29
|
+
require dir+'rubylog/simple_procedure'
|
30
|
+
require dir+'rubylog/variable'
|
31
|
+
require dir+'rubylog/structure'
|
27
32
|
|
28
33
|
# builtins
|
29
|
-
require 'rubylog/builtins
|
34
|
+
require dir+'rubylog/builtins/default'
|
35
|
+
|
36
|
+
# mixins
|
37
|
+
require dir+'rubylog/mixins/array'
|
38
|
+
require dir+'rubylog/mixins/class'
|
39
|
+
require dir+'rubylog/mixins/hash'
|
40
|
+
require dir+'rubylog/mixins/kernel'
|
41
|
+
require dir+'rubylog/mixins/method'
|
42
|
+
require dir+'rubylog/mixins/object'
|
43
|
+
require dir+'rubylog/mixins/proc'
|
44
|
+
require dir+'rubylog/mixins/string'
|
45
|
+
require dir+'rubylog/mixins/symbol'
|
30
46
|
|
31
|
-
require 'rubylog/clause.rb'
|
32
|
-
require 'array.rb'
|
33
|
-
require 'symbol.rb'
|
34
|
-
require 'proc.rb'
|
35
|
-
require 'object.rb'
|
36
|
-
require 'class.rb'
|
37
|
-
require 'method.rb'
|
38
47
|
|
39
|
-
Rubylog::Theory.new!
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "./lib/rubylog/builtins/file_system"
|
2
|
+
|
3
|
+
theory do
|
4
|
+
check "lib".dirname_in(".")
|
5
|
+
check "lib".filename_in(".").false
|
6
|
+
check "README.rdoc".filename_in(".")
|
7
|
+
check "README.rdoc".dirname_in(".").false
|
8
|
+
check (Dir.pwd+"/lib").dir_in(".")
|
9
|
+
check (Dir.pwd+"/lib").file_in(".").false
|
10
|
+
check (Dir.pwd+"/README.rdoc").file_in(".")
|
11
|
+
check (Dir.pwd+"/README.rdoc").dir_in(".").false
|
12
|
+
check (Dir.pwd+"/lib/rubylog.rb").file_in("lib")
|
13
|
+
check (Dir.pwd+"/lib/rubylog").dir_in("lib")
|
14
|
+
check "rubylog.rb".filename_in("lib")
|
15
|
+
check "rubylog".dirname_in("lib")
|
16
|
+
|
17
|
+
|
18
|
+
# this is removed in favor of string unification
|
19
|
+
#check "rubylog.rb".filename("rubylog", "rb")
|
20
|
+
#check A.filename("rubylog", "rb").and A.is "rubylog.rb"
|
21
|
+
#check "rubylog.rb".filename(F, "rb").and F.is "rubylog"
|
22
|
+
#check "rubylog.rb".filename("rubylog", E).and E.is "rb"
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "./lib/rubylog/builtins/reflection.rb"
|
2
|
+
|
3
|
+
theory do
|
4
|
+
functor_for String, :likes, :drinks
|
5
|
+
|
6
|
+
# fact
|
7
|
+
"John".likes! "beer"
|
8
|
+
check "John".likes("beer").fact
|
9
|
+
check { A.likes(B).fact.map{A.likes(B)} == ["John".likes("beer")] }
|
10
|
+
|
11
|
+
# follows_from
|
12
|
+
A.drinks(B).if A.likes(B)
|
13
|
+
check A.drinks(B).follows_from A.likes(B)
|
14
|
+
check {A.drinks(B).follows_from(K).map{K} == [A.likes(B)] }
|
15
|
+
|
16
|
+
# structure
|
17
|
+
check A.likes(B).structure(:likes, [A,B])
|
18
|
+
check { A.likes(B).structure(X,Y).map{[X,Y]} == [[:likes, [A,B]]] }
|
19
|
+
|
20
|
+
# structures with variable functor and partial argument list
|
21
|
+
check { K.structure(:drinks, ["John", "beer"]).map{K} == ["John".drinks("beer")] }
|
22
|
+
check { K.structure(A,[*B]).
|
23
|
+
and(A.is(:drinks)).
|
24
|
+
and(B.is(["John","beer"])).
|
25
|
+
map{K} == ["John".drinks("beer")] }
|
26
|
+
|
27
|
+
# variable
|
28
|
+
# Removed because of the "every built-in prediate is pure logical" principle
|
29
|
+
#check A.variable("A")
|
30
|
+
#check A.variable("B").false
|
31
|
+
#check { A.variable(B).map{B} == ["A"] }
|
32
|
+
# You can use the fact that automatic variable resolution yields nil if the
|
33
|
+
# variable is undefined:
|
34
|
+
#
|
35
|
+
# check A.is(ANY).and{ A }.false
|
36
|
+
# check A.is(ANY).and{ not A }
|
37
|
+
#
|
38
|
+
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
theory do
|
2
|
+
functor_for Integer, :divides
|
3
|
+
|
4
|
+
check { A.is_a? Rubylog::Variable }
|
5
|
+
check { A.rubylog_deep_dereference == A }
|
6
|
+
|
7
|
+
a = A
|
8
|
+
check { a.rubylog_deep_dereference.equal? a }
|
9
|
+
|
10
|
+
a.rubylog_unify(4) do
|
11
|
+
check { a.rubylog_deep_dereference == 4 }
|
12
|
+
check { [1,a].rubylog_deep_dereference == [1,4] }
|
13
|
+
check { a.divides(16).rubylog_deep_dereference == 4.divides(16) }
|
14
|
+
end
|
15
|
+
|
16
|
+
b = []
|
17
|
+
check { not b.rubylog_deep_dereference.equal? b }
|
18
|
+
|
19
|
+
c = Object.new
|
20
|
+
check { c.rubylog_deep_dereference.equal? c }
|
21
|
+
end
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "./lib/rubylog/builtins/file_system"
|
2
|
+
|
3
|
+
theory do
|
4
|
+
subject String
|
5
|
+
functor :dir, :contains
|
6
|
+
check_discontiguous false
|
7
|
+
|
8
|
+
".git".dir!.contains! "Git repository"
|
9
|
+
"bin".dir!.contains! "executables"
|
10
|
+
"examples".dir!.contains! "examples and ideas for different applications of Rubylog"
|
11
|
+
"lib".dir!.contains! "source code of Rubylog"
|
12
|
+
"spec".dir!.contains! "functional tests written in RSpec"
|
13
|
+
"logic".dir!.contains! "integration tests written in Rubylog"
|
14
|
+
|
15
|
+
gitignore = File.readlines(".gitignore").map{|l| l.chop}
|
16
|
+
check X.in(Y.dir.map{Y}).iff(X.in(Y.dirname_in(".").and(Y.not_in(gitignore)).map{Y}))
|
17
|
+
|
18
|
+
end
|
19
|
+
|
data/logic/dsl_logic.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
theory do
|
2
|
+
|
3
|
+
# prefix functors
|
4
|
+
|
5
|
+
prefix_functor :we_have
|
6
|
+
we_have! :weapons
|
7
|
+
we_have! :sunglasses
|
8
|
+
we_have! :rustling_leather_coats
|
9
|
+
|
10
|
+
check we_have :sunglasses
|
11
|
+
check { we_have? :rustling_leather_coats }
|
12
|
+
|
13
|
+
|
14
|
+
# built-in prefix functors
|
15
|
+
|
16
|
+
check all X.is(4).and(Y.is(X)), Y.is(4)
|
17
|
+
check any X.is(4)
|
18
|
+
check one(X.in([1,2,3])) { X % 2 == 0 }
|
19
|
+
check none X.in([1,2,3]), X.is(5)
|
20
|
+
|
21
|
+
check { all?(X.is(4)) { X < 5 } }
|
22
|
+
|
23
|
+
# variables
|
24
|
+
check A.is(ANY).and{ A == nil }
|
25
|
+
check A.is(4) .and{ A == 4 }
|
26
|
+
check B.is(4) .and{ A.is_a? Rubylog::Variable }
|
27
|
+
check B.is(ANY).and{ A.is_a? Rubylog::Variable }
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
theory do
|
2
|
+
functor_for String, :happy, :has
|
3
|
+
|
4
|
+
# syntax error
|
5
|
+
check { begin "John".happy.if; rescue Rubylog::SyntaxError; true else false end }
|
6
|
+
check { begin "John".happy.if!; rescue Rubylog::SyntaxError; true else false end }
|
7
|
+
check { begin "John".happy.unless; rescue Rubylog::SyntaxError; true else false end }
|
8
|
+
|
9
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
theory do
|
2
|
+
|
3
|
+
# class guard
|
4
|
+
functor_for Numeric, :divides
|
5
|
+
A[Integer].divides(B[Integer]).if { B % A == 0 }
|
6
|
+
A[Float].divides!(B[Float])
|
7
|
+
check 2.divides(10)
|
8
|
+
check 2.divides(9).false
|
9
|
+
check 2.divides(1).false
|
10
|
+
check 2.divides(0)
|
11
|
+
check 2.12.divides(4.5)
|
12
|
+
check -0.31.divides(-1.5)
|
13
|
+
check 0.3.divides(3).false
|
14
|
+
check 2.0.divides(10).false
|
15
|
+
check 2.divides(10.0).false
|
16
|
+
check 2.divides(9.0).false
|
17
|
+
|
18
|
+
# union of guards at compile
|
19
|
+
functor_for Numeric, :small
|
20
|
+
A[0...100].small.if ANY.is A[Integer]
|
21
|
+
check 0.small
|
22
|
+
check 10.small
|
23
|
+
check -1.small.false
|
24
|
+
check 0.0.small.false
|
25
|
+
check 99.small
|
26
|
+
check 99.0.small.false
|
27
|
+
check 99.9.small.false
|
28
|
+
check 100.small.false
|
29
|
+
check 100.0.small.false
|
30
|
+
|
31
|
+
# union of guards at compile (dont-care)
|
32
|
+
functor_for Numeric, :small
|
33
|
+
A[0...100].small.if A.is ANY[Integer]
|
34
|
+
check 0.small
|
35
|
+
check 10.small
|
36
|
+
check -1.small.false
|
37
|
+
check 0.0.small.false
|
38
|
+
check 99.small
|
39
|
+
check 99.0.small.false
|
40
|
+
check 99.9.small.false
|
41
|
+
check 100.small.false
|
42
|
+
check 100.0.small.false
|
43
|
+
|
44
|
+
# union of guards at unification
|
45
|
+
self[[:small,1]].clear
|
46
|
+
functor_for Numeric, :small
|
47
|
+
A[0...100].small.if A.is B[Integer]
|
48
|
+
check 0.small
|
49
|
+
check 10.small
|
50
|
+
check -1.small.false
|
51
|
+
check 0.0.small.false
|
52
|
+
check 99.small
|
53
|
+
check 99.0.small.false
|
54
|
+
check 99.9.small.false
|
55
|
+
check 100.small.false
|
56
|
+
check 100.0.small.false
|
57
|
+
|
58
|
+
# union of guards at unification (reversed)
|
59
|
+
self[[:small,1]].clear
|
60
|
+
functor_for Numeric, :small
|
61
|
+
A[0...100].small.if B[Integer].is A
|
62
|
+
check 0.small
|
63
|
+
check 10.small
|
64
|
+
check -1.small.false
|
65
|
+
check 0.0.small.false
|
66
|
+
check 99.small
|
67
|
+
check 99.0.small.false
|
68
|
+
check 99.9.small.false
|
69
|
+
check 100.small.false
|
70
|
+
check 100.0.small.false
|
71
|
+
|
72
|
+
|
73
|
+
# proc guards
|
74
|
+
functor_for Numeric, :big
|
75
|
+
A[proc{|a|a > 20}].big!
|
76
|
+
check -100.big.false
|
77
|
+
check 0.big.false
|
78
|
+
check 10.big.false
|
79
|
+
check 20.big.false
|
80
|
+
check 21.big
|
81
|
+
check 200.big
|
82
|
+
|
83
|
+
# hash guards
|
84
|
+
functor_for String, :char
|
85
|
+
S[length: 1].char!
|
86
|
+
check "a".char
|
87
|
+
check " ".char
|
88
|
+
check "".char.false
|
89
|
+
check "af".char.false
|
90
|
+
check "Hello".char.false
|
91
|
+
|
92
|
+
# list hash guards
|
93
|
+
functor_for String, :capitalized
|
94
|
+
S[[:[],0] => /[A-Z]/].capitalized!
|
95
|
+
check "a".capitalized.false
|
96
|
+
check " ".capitalized.false
|
97
|
+
check "".capitalized.false
|
98
|
+
check "af".capitalized.false
|
99
|
+
check "A".capitalized
|
100
|
+
check "Hello".capitalized
|
101
|
+
|
102
|
+
|
103
|
+
# chained hash guards
|
104
|
+
functor_for String, :funny
|
105
|
+
S[upcase: {[:[],1..-2] => "ELL"}].funny!
|
106
|
+
check "hello".funny
|
107
|
+
check "Bell!".funny
|
108
|
+
check "BELL!".funny
|
109
|
+
check "DELL".funny.false
|
110
|
+
check "help!".funny.false
|
111
|
+
check "hello!".funny.false
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
end
|
data/logic/list_logic.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
theory do
|
2
|
+
check [1,2,3].is [1,2,3]
|
3
|
+
check {[1,2,3].is([A,B,C]).map{[A,B,C]} == [[1,2,3]]}
|
4
|
+
check [].is []
|
5
|
+
|
6
|
+
check [1,2,3].is_not [1,2,4]
|
7
|
+
check [1,2,3].is_not [1,2]
|
8
|
+
check [1,2,3].is_not [1,ANY]
|
9
|
+
check [1,2,3].is [1,2,ANY]
|
10
|
+
|
11
|
+
# splats
|
12
|
+
check { [1,2,3].is([1,*A]).map{A} == [[2,3]] }
|
13
|
+
check [].is_not [A,*ANY]
|
14
|
+
check [].is [*ANY]
|
15
|
+
check [2].is [2, *ANY]
|
16
|
+
check [2, *ANY].is [2]
|
17
|
+
check [1,2].is([A,*B]).and A.is(1).and B.is([2])
|
18
|
+
|
19
|
+
# [*A] = [*B]
|
20
|
+
check {[*A].is([*B]).and A.is([1,2]).map{B} == [[1,2]]}
|
21
|
+
check [*A].is [*B]
|
22
|
+
check { [*A].is([*B]).each { } } # no infinite recursion
|
23
|
+
|
24
|
+
|
25
|
+
# append
|
26
|
+
check {[1,2,3].is([*A,*B]).map{[A,B]} == [[[],[1,2,3]],[[1],[2,3]],[[1,2],[3]],[[1,2,3],[]]] }
|
27
|
+
check [1,2,3].is [Rubylog::DSL::ArraySplat.new([1,2]),*ANY]
|
28
|
+
check [1,2,3].is [Rubylog::DSL::ArraySplat.new([1,2,3]),*ANY]
|
29
|
+
check [1,2,3].is_not [Rubylog::DSL::ArraySplat.new([1,2,3,B]),*ANY]
|
30
|
+
|
31
|
+
# member
|
32
|
+
check [1,2,3].is [*ANY,2,*ANY]
|
33
|
+
check X.is([1,2,3]).and A.in(X).all X.is [*ANY,A,*ANY]
|
34
|
+
|
35
|
+
# palindromes
|
36
|
+
functor_for Array, :palindrome
|
37
|
+
[].palindrome!
|
38
|
+
[ANY].palindrome!
|
39
|
+
[A,*X,A].palindrome.if X.palindrome
|
40
|
+
check X.in([[], [1], [1,1], [1,2,1], [1,2,2,1], [1,2,3,2,1], [1,2,3,3,2,1]]).all X.palindrome
|
41
|
+
check X.in([[1,2], [1,3,4,1], [2,2,5]]).none X.palindrome
|
42
|
+
|
43
|
+
# legacy syntax
|
44
|
+
check { [1,2,3].is([1]+A).map{A} == [[2,3]] }
|
45
|
+
check [].is_not [A]+ANY
|
46
|
+
check [].is []+ANY
|
47
|
+
check [2].is [2]+ANY
|
48
|
+
check(([2]+ANY).is [2])
|
49
|
+
check [1,2].is([A]+B).and A.is(1).and B.is([2])
|
50
|
+
check {([]+A).is([]+B).and A.is([1,2]).map{B} == [[1,2]]}
|
51
|
+
check(([]+A).is([]+B))
|
52
|
+
check {([]+A).is([]+B).each { } }
|
53
|
+
check {[1,2,3].is([]+A+B).map{[A,B]} == [[[],[1,2,3]],[[1],[2,3]],[[1,2],[3]],[[1,2,3],[]]] }
|
54
|
+
check X.is([1,2,3]).and A.in(X).all X.is []+ANY+[A]+ANY
|
55
|
+
end
|
data/logic/map_logic.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
theory "Rubylog::MapLogic" do
|
2
|
+
functor :likes
|
3
|
+
subject Symbol
|
4
|
+
|
5
|
+
# inriausite^findall
|
6
|
+
check S.is{X.is(1).or(X.is(2)).map{X}}.and{S == [1,2]}
|
7
|
+
check S.is{X.is(:john).map{X.likes(Y)}}.and{S == [:john.likes(Y)]}
|
8
|
+
check G.is(:fail.or :fail).and L.is{G.map{X}}.and{L == []}
|
9
|
+
check S.is{X.is(1).or(X.is(1)).map{X}}.and{S == [1,1]}
|
10
|
+
check [1,2].is{X.is(2).or(X.is(1)).map{X}}.false
|
11
|
+
check [X,Y].is{A.is(1).or(A.is(2)).map{A}}.and{X == 1}.and{Y == 2}
|
12
|
+
(S.is {Goal.map{X}}).solve and check :fail rescue NoMethodError
|
13
|
+
(S.is {4.map{X}}).solve and check :fail rescue NoMethodError
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
load "lib/rubylog/theory.rb"
|
2
|
+
A = theory do
|
3
|
+
functor_for Symbol, :good
|
4
|
+
|
5
|
+
:x.good!
|
6
|
+
end
|
7
|
+
|
8
|
+
B = theory do
|
9
|
+
:y.good!
|
10
|
+
end
|
11
|
+
|
12
|
+
theory do
|
13
|
+
multitheory [:good,1]
|
14
|
+
|
15
|
+
check { self[[:good,1]].multitheory? }
|
16
|
+
|
17
|
+
include A
|
18
|
+
include B
|
19
|
+
|
20
|
+
check { self[[:good,1]].multitheory? }
|
21
|
+
|
22
|
+
check {X.good.map{X} == [:x,:y]}
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
theory do
|
2
|
+
functor_for Integer, :factorial
|
3
|
+
0.factorial! 1
|
4
|
+
N.factorial(K).if proc{N > 0}.and N1.is {N-1} .and N1.factorial(K1).and K.is{ N*K1 }
|
5
|
+
|
6
|
+
check 0.factorial 1
|
7
|
+
check 1.factorial 1
|
8
|
+
check 2.factorial 2
|
9
|
+
check 3.factorial 6
|
10
|
+
check 4.factorial 24
|
11
|
+
check 7.factorial 5040
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
theory do
|
2
|
+
check "asdf".is "asdf"
|
3
|
+
check { "abc#{S}def" =~ /abc.S\[\].def/ }
|
4
|
+
check { "abc#{S[length: 1]}def" =~ /abc.S\[\d+\].def/ }
|
5
|
+
check { "h#{S}o".is("hello").map{S} == ["ell"] }
|
6
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Base} == ["hello"] }
|
7
|
+
|
8
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Ext} == ["rb"] }
|
9
|
+
check { "h#{S}o".is("auto").map{S} == [] }
|
10
|
+
|
11
|
+
# backtracked matches
|
12
|
+
check { "abc".is("#{A}#{B}").map{"#{A}:#{B}"} == [":abc","a:bc","ab:c","abc:"] }
|
13
|
+
check { "www.google.com".is("#{A}.#{B}").map{[A,B]} == [["www", "google.com"],["www.google", "com"]] }
|
14
|
+
check { "a".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == ["::a",":a:","a::"] }
|
15
|
+
check { "ab".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == %w(::ab :a:b :ab: a::b a:b: ab::) }
|
16
|
+
|
17
|
+
# guards
|
18
|
+
check { "abc".is("#{A[/\A.\z/]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
19
|
+
check { "abc".is("#{A[length: 1]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
20
|
+
|
21
|
+
|
22
|
+
# palindromes
|
23
|
+
functor_for String, :palindrome
|
24
|
+
|
25
|
+
S[empty?: true].palindrome!
|
26
|
+
S[length: 1].palindrome!
|
27
|
+
S[lambda{|s|s.length > 1}].palindrome.if S.is("#{A[length: 1]}#{B}#{A}").and B.palindrome
|
28
|
+
|
29
|
+
check "".palindrome
|
30
|
+
check "dd".palindrome
|
31
|
+
check "aba".palindrome
|
32
|
+
check "faaf".palindrome
|
33
|
+
check "ffaaff".palindrome
|
34
|
+
check "rererer".palindrome
|
35
|
+
check "lol".palindrome
|
36
|
+
check "ji".palindrome.false
|
37
|
+
check "doo".palindrome.false
|
38
|
+
check "taaaz".palindrome.false
|
39
|
+
check "faad".palindrome.false
|
40
|
+
check "rerere".palindrome.false
|
41
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "./lib/rubylog/builtins/file_system"
|
2
|
+
|
3
|
+
theory do
|
4
|
+
functor_for Integer, :factorial
|
5
|
+
|
6
|
+
# one level
|
7
|
+
check 4.is(ANY[Integer,thats < 10])
|
8
|
+
check 4.is(ANY[Integer,thats < 5])
|
9
|
+
check 4.is(ANY[Integer,thats < 4]).false
|
10
|
+
check 4.is(ANY[Integer,thats < 2]).false
|
11
|
+
|
12
|
+
# question mark
|
13
|
+
check "".is(ANY[thats.empty?])
|
14
|
+
check "a".is(ANY[thats.empty?]).false
|
15
|
+
|
16
|
+
# two levels
|
17
|
+
check "hello".is(ANYTHING[thats.reverse == "olleh"])
|
18
|
+
check "hello".is(ANYTHING[thats.reverse == "olle"]).false
|
19
|
+
|
20
|
+
# four levels
|
21
|
+
check "hello".is(ANY[thats.upcase.partition("E")[0] == "H"])
|
22
|
+
check "hello".is(ANY[thats.upcase.partition("E")[1] == "E"])
|
23
|
+
check "hello".is(ANY[thats.upcase.partition("E")[2] == "LLO"])
|
24
|
+
check "hello".is(ANY[thats.upcase.partition("E")[1] == "H"]).false
|
25
|
+
check "hello".is(ANY[thats.upcase.partition("E")[0] == "h"]).false
|
26
|
+
check "hello".is(ANY[thats.upcase.partition("L")[0] == "H"]).false
|
27
|
+
check "hello".is(ANY[thats.upcase.partition("e")[0] == "H"]).false
|
28
|
+
|
29
|
+
# files
|
30
|
+
check { "#{S[String, thats.start_with?(".")]}".filename_in(".").map{S}.include? ".gitignore" }
|
31
|
+
check { not "#{S[String, thats.start_with?(".")]}".filename_in(".").map{S}.include? "lib" }
|
32
|
+
check { "#{S[/\A(.*)\.rb/]}".filename_in("lib").map{S} == ["rubylog.rb"] }
|
33
|
+
|
34
|
+
# factorial
|
35
|
+
0.factorial! 1
|
36
|
+
K[thats > 0].factorial(N).if K0.is{K-1}.and K0.factorial(N0).and N.is{N0*K}
|
37
|
+
|
38
|
+
# palindrome
|
39
|
+
functor_for String, :palindrome
|
40
|
+
S[String, thats.length <= 1].palindrome!
|
41
|
+
"#{A[thats.length == 1]}#{B}#{A}".palindrome.if B.palindrome
|
42
|
+
|
43
|
+
check "a".palindrome
|
44
|
+
check "aa".palindrome
|
45
|
+
check "aga".palindrome
|
46
|
+
check "aaa".palindrome
|
47
|
+
check "avava".palindrome
|
48
|
+
check "ab".palindrome.false
|
49
|
+
check "abb".palindrome.false
|
50
|
+
check "abab".palindrome.false
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
theory do
|
2
|
+
# dont-care variables case insensitive ANY* and _*
|
3
|
+
check 3.is(ANY).and 3.is(ANY)
|
4
|
+
check 3.is(ANY).and 4.is(ANY)
|
5
|
+
check 3.is(ANYTHING).and 3.is(ANYTHING)
|
6
|
+
check 3.is(ANYTHING).and 4.is(ANYTHING)
|
7
|
+
check 3.is(Anything).and 3.is(Anything)
|
8
|
+
check 3.is(Anything).and 4.is(Anything)
|
9
|
+
check 3.is(Rubylog::Variable.new(:_var1)).and(3.is(Rubylog::Variable.new(:_var1)))
|
10
|
+
check 3.is(Rubylog::Variable.new(:_var1)).and(4.is(Rubylog::Variable.new(:_var1)))
|
11
|
+
check 3.is(Rubylog::Variable.new(:var1 )).and(3.is(Rubylog::Variable.new(:var1 )))
|
12
|
+
check 3.is(Rubylog::Variable.new(:var1 )).and(4.is(Rubylog::Variable.new(:var1 ))).false
|
13
|
+
|
14
|
+
# dont-care variables support recursion
|
15
|
+
functor_for Integer, :factorial
|
16
|
+
0.factorial! 1
|
17
|
+
N.factorial(K).if proc{N > 0}.and N1.is {N-1} .and N1.factorial(K1).and K.is{ N*K1 }.and K.is(ANY1).and N.is(ANY2)
|
18
|
+
check 0.factorial 1
|
19
|
+
check 1.factorial 1
|
20
|
+
check 2.factorial 2
|
21
|
+
check 3.factorial 6
|
22
|
+
check 4.factorial 24
|
23
|
+
check 7.factorial 5040
|
24
|
+
end
|