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.
Files changed (163) hide show
  1. data/Gemfile +3 -12
  2. data/Gemfile.lock +22 -48
  3. data/README.rdoc +38 -38
  4. data/README.rdoc.orig +284 -0
  5. data/RELEASE_NOTES.rdoc +51 -0
  6. data/Rakefile +14 -18
  7. data/TODO.txt +0 -0
  8. data/VERSION +1 -1
  9. data/examples/a_plus_b.rb +6 -0
  10. data/examples/checkmate.rb +88 -0
  11. data/examples/combination.rb +17 -0
  12. data/examples/dcg.rb +3 -2
  13. data/examples/dcg2.rb +2 -2
  14. data/{logic → examples}/directory_structure_logic.rb +3 -5
  15. data/examples/dirlist.rb +4 -0
  16. data/examples/divisors.rb +6 -0
  17. data/examples/enumerators.rb +3 -3
  18. data/examples/factorial.rb +2 -3
  19. data/examples/file_search.rb +14 -0
  20. data/examples/hanoi.rb +4 -5
  21. data/examples/hello.rb +6 -4
  22. data/examples/mice.rb +92 -0
  23. data/examples/mice2.rb +19 -0
  24. data/examples/n_queens.rb +32 -0
  25. data/examples/object_oriented.rb +14 -0
  26. data/examples/palindrome_detection.rb +18 -0
  27. data/examples/parsing.rb +6 -4
  28. data/examples/permutation.rb +12 -0
  29. data/examples/prefix.rb +13 -0
  30. data/examples/primality_by_division.rb +22 -0
  31. data/examples/primitives.rb +10 -8
  32. data/examples/sieve_of_eratosthenes.rb +14 -0
  33. data/examples/string_interpolation.rb +4 -0
  34. data/examples/sudoku.rb +52 -0
  35. data/examples/tracing.rb +19 -0
  36. data/lib/rspec/rubylog.rb +29 -0
  37. data/lib/rubylog/assertable.rb +24 -0
  38. data/lib/rubylog/builtins/arithmetics.rb +63 -0
  39. data/lib/rubylog/builtins/assumption.rb +71 -0
  40. data/lib/rubylog/builtins/ensure.rb +13 -0
  41. data/lib/rubylog/builtins/file_system.rb +30 -8
  42. data/lib/rubylog/builtins/logic.rb +69 -38
  43. data/lib/rubylog/builtins/reflection.rb +35 -50
  44. data/lib/rubylog/builtins/term.rb +15 -17
  45. data/lib/rubylog/builtins.rb +11 -0
  46. data/lib/rubylog/clause.rb +19 -0
  47. data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
  48. data/lib/rubylog/context.rb +24 -0
  49. data/lib/rubylog/context_creation.rb +71 -0
  50. data/lib/rubylog/context_modules/checks.rb +35 -0
  51. data/lib/rubylog/context_modules/demonstration.rb +16 -0
  52. data/lib/rubylog/context_modules/predicates.rb +86 -0
  53. data/lib/rubylog/context_modules/primitives.rb +18 -0
  54. data/lib/rubylog/context_modules/thats.rb +13 -0
  55. data/lib/rubylog/default_context.rb +9 -0
  56. data/lib/rubylog/dsl/array_splat.rb +11 -3
  57. data/lib/rubylog/dsl/primitives.rb +24 -12
  58. data/lib/rubylog/dsl/thats.rb +6 -0
  59. data/lib/rubylog/dsl/variables.rb +56 -21
  60. data/lib/rubylog/errors.rb +26 -15
  61. data/lib/rubylog/mixins/array.rb +95 -62
  62. data/lib/rubylog/mixins/kernel.rb +3 -2
  63. data/lib/rubylog/mixins/method.rb +0 -1
  64. data/lib/rubylog/mixins/object.rb +2 -1
  65. data/lib/rubylog/mixins/proc.rb +9 -12
  66. data/lib/rubylog/mixins/string.rb +15 -23
  67. data/lib/rubylog/mixins/symbol.rb +7 -24
  68. data/lib/rubylog/nullary_predicates.rb +3 -0
  69. data/lib/rubylog/predicate.rb +53 -0
  70. data/lib/rubylog/primitive.rb +15 -0
  71. data/lib/rubylog/procedure.rb +42 -0
  72. data/lib/rubylog/rule.rb +24 -0
  73. data/lib/rubylog/structure.rb +19 -38
  74. data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
  75. data/lib/rubylog/tracing.rb +75 -0
  76. data/lib/rubylog/variable.rb +31 -12
  77. data/lib/rubylog.rb +36 -32
  78. data/rubylog.gemspec +92 -84
  79. data/spec/inriasuite_spec.rb +906 -9
  80. data/spec/integration/custom_classes_spec.rb +61 -0
  81. data/spec/integration/dsl_spec.rb +38 -0
  82. data/spec/integration/recursion_spec.rb +14 -0
  83. data/spec/integration/theory_as_module_spec.rb +20 -0
  84. data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
  85. data/spec/rspec/rubylog_spec.rb +75 -0
  86. data/spec/rubylog/assertable_spec.rb +111 -0
  87. data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
  88. data/spec/rubylog/builtins/assumption_spec.rb +70 -0
  89. data/spec/rubylog/builtins/ensure_spec.rb +8 -0
  90. data/spec/rubylog/builtins/file_system_spec.rb +40 -0
  91. data/spec/rubylog/builtins/logic_spec.rb +340 -0
  92. data/spec/rubylog/builtins/reflection_spec.rb +43 -0
  93. data/spec/rubylog/builtins/term_spec.rb +85 -0
  94. data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
  95. data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
  96. data/spec/rubylog/context_modules/thats_spec.rb +94 -0
  97. data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
  98. data/spec/rubylog/dsl/primitives_spec.rb +43 -0
  99. data/spec/rubylog/errors_spec.rb +18 -0
  100. data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
  101. data/spec/rubylog/mixins/array_spec.rb +80 -0
  102. data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
  103. data/spec/rubylog/mixins/proc_spec.rb +59 -0
  104. data/spec/rubylog/mixins/string_spec.rb +48 -0
  105. data/spec/rubylog/mixins/symbol_spec.rb +9 -0
  106. data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
  107. data/spec/rubylog/term_spec.rb +7 -0
  108. data/spec/rubylog/tracing_spec.input +27 -0
  109. data/spec/rubylog/tracing_spec.rb +44 -0
  110. data/spec/rubylog/variable_spec.rb +279 -0
  111. data/spec/spec_helper.rb +1 -0
  112. data/vimrc +11 -0
  113. metadata +103 -123
  114. data/README.hu.rb +0 -58
  115. data/bin/rubylog +0 -18
  116. data/examples/theory.rb +0 -32
  117. data/lib/rubylog/builtins/default.rb +0 -10
  118. data/lib/rubylog/dsl.rb +0 -70
  119. data/lib/rubylog/interfaces/assertable.rb +0 -16
  120. data/lib/rubylog/interfaces/callable.rb +0 -18
  121. data/lib/rubylog/interfaces/predicate.rb +0 -8
  122. data/lib/rubylog/interfaces/procedure.rb +0 -60
  123. data/lib/rubylog/mixins/class.rb +0 -11
  124. data/lib/rubylog/simple_procedure.rb +0 -8
  125. data/lib/rubylog/theory.rb +0 -422
  126. data/logic/builtins/file_system_logic.rb +0 -23
  127. data/logic/builtins/reflection_logic.rb +0 -40
  128. data/logic/dereference_logic.rb +0 -23
  129. data/logic/dsl_logic.rb +0 -29
  130. data/logic/errors_logic.rb +0 -9
  131. data/logic/guard_logic.rb +0 -115
  132. data/logic/list_logic.rb +0 -55
  133. data/logic/map_logic.rb +0 -15
  134. data/logic/multitheory.rb +0 -23
  135. data/logic/recursion_logic.rb +0 -12
  136. data/logic/string_logic.rb +0 -41
  137. data/logic/thats_logic.rb +0 -51
  138. data/logic/variable_logic.rb +0 -24
  139. data/spec/bartak_guide_spec.rb +0 -86
  140. data/spec/builtins/all_spec.rb +0 -99
  141. data/spec/builtins/and_spec.rb +0 -22
  142. data/spec/builtins/array_spec.rb +0 -16
  143. data/spec/builtins/branch_or_spec.rb +0 -27
  144. data/spec/builtins/cut_spec.rb +0 -44
  145. data/spec/builtins/fail_spec.rb +0 -5
  146. data/spec/builtins/false_spec.rb +0 -5
  147. data/spec/builtins/in_spec.rb +0 -38
  148. data/spec/builtins/is_false_spec.rb +0 -12
  149. data/spec/builtins/is_spec.rb +0 -26
  150. data/spec/builtins/matches_spec.rb +0 -23
  151. data/spec/builtins/or_spec.rb +0 -22
  152. data/spec/builtins/splits_to.rb +0 -18
  153. data/spec/builtins/then_spec.rb +0 -27
  154. data/spec/builtins/true_spec.rb +0 -5
  155. data/spec/compilation_spec.rb +0 -61
  156. data/spec/custom_classes_spec.rb +0 -43
  157. data/spec/dereference.rb +0 -10
  158. data/spec/queries_spec.rb +0 -150
  159. data/spec/recursion_spec.rb +0 -18
  160. data/spec/ruby_code_spec.rb +0 -52
  161. data/spec/rules_spec.rb +0 -97
  162. data/spec/theory_spec.rb +0 -29
  163. data/spec/variable_spec.rb +0 -26
@@ -0,0 +1,88 @@
1
+ require "rubylog"
2
+
3
+
4
+ rubylog do
5
+ predicate_for Array, ".on()"
6
+
7
+ black, white = 0, 1
8
+ pawn,rook,knight,bishop,queen,king = :pawn, :rook, :knight, :bishop, :queen, :king
9
+
10
+ mark = :mark
11
+
12
+ signs = {pawn: "p", rook:"r", knight:"n", bishop:"b", queen:"q", king:"k", mark:"x"}
13
+
14
+ [black,pawn] .on! [5,7]
15
+ [black,bishop].on! [8,1]
16
+ [black,pawn] .on! [8,5]
17
+ [black,king] .on! [8,6]
18
+
19
+ [white,pawn] .on! [1,7]
20
+ [white,king] .on! [1,8]
21
+ [white,bishop].on! [2,8]
22
+ [white,pawn] .on! [3,7]
23
+ [white,pawn] .on! [5,5]
24
+ [white,pawn] .on! [6,6]
25
+ [white,knight].on! [6,8]
26
+ [white,bishop].on! [7,2]
27
+ [white,pawn] .on! [7,7]
28
+ [white,pawn] .on! [8,4]
29
+
30
+ predicate ":show"
31
+
32
+ :show.if do
33
+ (R_.in(1..8).and(R.is{9-R_})).each do
34
+ F.in(1..8).each do
35
+ print '.' unless prove [C,P].on([F,R]).and :cut!.and { print C==white ? signs[P].upcase : signs[P]; true }
36
+ end
37
+ puts
38
+ end
39
+ puts
40
+ true
41
+ end
42
+
43
+ functor_for Rubylog::Structure, :attacks, :can_move_to
44
+ functor_for Integer, :rook_move, :bishop_move, :squares, :squares_forward
45
+ prefix_functor :knight_move, :pawn_attack, :pawn_move
46
+
47
+
48
+ [C,king ].on(S).can_move_to(S1).if 1. rook_move(S,S1).or 1.bishop_move(S,S1)
49
+ [C,queen ].on(S).can_move_to(S1).if ANY. rook_move(S,S1).or ANY.bishop_move(S,S1)
50
+ [C,bishop ].on(S).can_move_to(S1).if ANY.bishop_move(S,S1)
51
+ [C,knight ].on(S).can_move_to(S1).if knight_move(S,S1)
52
+ [C,rook ].on(S).can_move_to(S1).if ANY. rook_move(S,S1)
53
+
54
+ [white,pawn].on(S).can_move_to(S1).if pawn_move(S,S1)
55
+ [black,pawn].on(S).can_move_to(S1).if pawn_move(S1,S)
56
+ [white,pawn].on([F,2]).can_move_to!([F,4])
57
+ [black,pawn].on([F,7]).can_move_to!([F,5])
58
+
59
+ [white,pawn].on(S).attacks(S1).if! pawn_attack(S,S1)
60
+ [black,pawn].on(S).attacks(S1).if! pawn_attack(S1,S)
61
+ X.attacks(S1).if X.can_move_to(S1)
62
+
63
+
64
+ N.squares_forward(A[1..8],B[1..8]).if B.is(A,:+,N)
65
+ N.squares(A,B).if A.in(1..8).and B.in(1..8).and B.is(A,:+,N).or A.is(B,:+,N)
66
+
67
+ N. rook_move([F ,R1],[F ,R2]).if N.squares(R1,R2)
68
+ N. rook_move([F1,R ],[F2,R ]).if N.squares(F1,F2)
69
+ N.bishop_move([F1,R1],[F2,R2]).if N.squares(R1,R2).and N.squares(F1,F2)
70
+
71
+ knight_move([F1,R1],[F2,R2]).if((1.squares(F1,F2).and 2.squares(R1,R2))
72
+ .or(1.squares(R1,R2).and 2.squares(F1,F2)))
73
+ pawn_move( [F ,R1],[F ,R2]).if 1.squares_forward(R1,R2)
74
+ pawn_attack([F1,R1],[F2,R2]).if R2.is(R1,:+,1).and 1.squares(F1,F2)
75
+
76
+
77
+ functor_for Rubylog::Structure, :moved_to
78
+
79
+ [C,P].on(S).moved_to(S1).if [C,P].on(S).and [C,P].on(S).can_move_to(S1).and [C,P].on(S).revoked.and [C,P].on(S1).assumed
80
+
81
+ solve :show.and [C,P].on(S).moved_to(S1).and{ puts "#{C} #{P}: #{S} -> #{S1}"; true}.and :show
82
+
83
+
84
+
85
+
86
+
87
+
88
+ end
@@ -0,0 +1,17 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for Array, ".choose(,,)"
5
+ predicate_for Integer, ".one_less_than()"
6
+
7
+ N.one_less_than(M).if M.sum_of(N,1)
8
+
9
+ L.choose!(0,[],L)
10
+ [A,*REST].choose(N[thats>0],CHOSEN,[A,*REM]).if REST.choose(N,CHOSEN,REM)
11
+ [A,*REST].choose(N[thats>0],[A,*CHOSEN],REM).if N1.one_less_than(N).and REST.choose(N1,CHOSEN,REM)
12
+
13
+ [1,2,3,4,5].choose(3,L,ANY).each do
14
+ L.choose(1,[A],REM).each do
15
+ puts "#{A}: #{REM}"
16
+ end
17
+ end
data/examples/dcg.rb CHANGED
@@ -1,8 +1,9 @@
1
+ require "rubylog"
1
2
  # This is a quick and dirty solution to replace Prolog's DCG syntax.
2
3
  # It is slow for long inputs. See examples/dcg2.rb for a more efficient algorithm (the same as Prolog's DCG).
3
4
 
4
- theory do
5
- functor_for Array, :sentence, :subject, :object, :nominal_phrase, :noun, :verb, :article
5
+ rubylog do
6
+ predicate_for Array, ".sentence", ".subject", ".object", ".nominal_phrase", ".noun", ".verb", ".article"
6
7
 
7
8
  [*S,*V,*O].sentence.if S.subject.and V.verb.and O.object
8
9
  S.subject.if S.nominal_phrase
data/examples/dcg2.rb CHANGED
@@ -4,8 +4,8 @@
4
4
  $:.unshift File.dirname(__FILE__)+"/../lib"
5
5
  require 'rubylog'
6
6
 
7
- theory do
8
- functor_for Array, :sentence, :subject, :object, :nominal_phrase, :noun, :verb, :article
7
+ rubylog do
8
+ predicate_for Array, ".sentence()", ".subject()", ".object()", ".nominal_phrase()", ".noun()", ".verb()", ".article()"
9
9
 
10
10
  # sentence --> subject, verb, object
11
11
  Se.sentence(L3).if Se.subject(L1).and L1.verb(L2).and L2.object(L3)
@@ -1,9 +1,7 @@
1
- require "./lib/rubylog/builtins/file_system"
1
+ require "rubylog"
2
2
 
3
- theory do
4
- subject String
5
- functor :dir, :contains
6
- check_discontiguous false
3
+ rubylog do
4
+ predicate_for String, ".dir", ".contains()"
7
5
 
8
6
  ".git".dir!.contains! "Git repository"
9
7
  "bin".dir!.contains! "executables"
@@ -0,0 +1,4 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+
@@ -0,0 +1,6 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
3
+
4
+ extend Rubylog::Context
5
+
6
+ p (P.is(672).and A.in{1..P}.and P.product_of(A,B).and{A<=B}).count
@@ -1,9 +1,9 @@
1
1
  $:.unshift File.dirname(__FILE__)+"/../lib"
2
2
  require 'rubylog'
3
3
 
4
- theory do
5
- subject Symbol
6
- functor :likes
4
+ rubylog do
5
+ self.default_subject = Symbol
6
+ predicate ".likes()"
7
7
 
8
8
  :john.likes! :beer
9
9
  :john.likes! :milk
@@ -1,9 +1,8 @@
1
1
  $:.unshift File.dirname(__FILE__)+"/../lib"
2
2
  require 'rubylog'
3
3
 
4
- FactorialTheory = theory do
5
- subject Integer
6
- functor :factorial
4
+ rubylog do
5
+ predicate_for Integer, ".factorial()"
7
6
 
8
7
  0.factorial! 1
9
8
  N[thats > 0].factorial(K).if \
@@ -0,0 +1,14 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for String, "FILE.found_in(DIR)"
5
+
6
+ FILE.found_in(DIR).if FILE.file_in(DIR)
7
+ FILE.found_in(DIR).if DIR2[thats_not =~ /\/\./].dir_in(DIR).and FILE.found_in(DIR2)
8
+
9
+ "lib/#{X}.rb".found_in("lib").and "lib/#{X}"
10
+ "#{X}/spec/#{S}_spec.rb".found_in("spec").each do
11
+ puts S
12
+ end
13
+
14
+
data/examples/hanoi.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  $:.unshift File.dirname(__FILE__)+"/../lib"
2
2
  require "rubylog"
3
3
 
4
- theory do
5
- functor_for Integer, :move, :hanoi
6
- prefix_functor :write_info
4
+ rubylog do
5
+ predicate_for Integer, ".move(,,)", ".hanoi"
7
6
 
8
7
  0.move(ANY,ANY,ANY).if :cut!
9
8
  N.move(A,B,C).if (
@@ -15,10 +14,10 @@ theory do
15
14
  N.hanoi.if N.move('left', 'right', 'center')
16
15
 
17
16
  puts "\nWhat's the solution for a single disc?"
18
- prove 1.hanoi
17
+ solve 1.hanoi
19
18
 
20
19
  puts "\n\nWhat's the solution for 5 discs?"
21
- prove 5.hanoi
20
+ solve 5.hanoi
22
21
 
23
22
 
24
23
  end
data/examples/hello.rb CHANGED
@@ -3,13 +3,15 @@ $:.unshift File.dirname(__FILE__)+"/../lib"
3
3
  require 'rubylog'
4
4
 
5
5
 
6
- HelloTheory = theory do
7
- functor_for String, :written
6
+ rubylog do
7
+ predicate_for String, ".written :hello"
8
8
 
9
9
  X.written.if {puts X; true}
10
10
 
11
- :hello.if "Hello, world!".written
11
+ :hello.if "Hello world!".written
12
12
  end
13
13
 
14
- HelloTheory.prove :hello
14
+ rubylog do
15
+ solve :hello
16
+ end
15
17
 
data/examples/mice.rb ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__)+"/../lib"
3
+ # This is a solution for a math problem.
4
+ #
5
+ # Mafia the black cat plays a game. She has N cups with 0 or 1 mouse under each.
6
+ # She peeks under some cups one by one to see if there is a mouse under them.
7
+ # What she wants to find out is whether there are two cups next to each other
8
+ # which both have a mouse. She found that for some number of cups she has to
9
+ # peek under every cup to decide if there are two adjacent ones with a mouse.
10
+ # In this case she considers the task hard. For which N's does she consider it
11
+ # hard (N<=2013)?
12
+
13
+ require "rubylog"
14
+ require "rubylog/builtins/assumption"
15
+ extend Rubylog::Context
16
+
17
+
18
+ class Cup < Struct.new :i
19
+ extend Rubylog::Context
20
+
21
+ def inspect
22
+ "##{i}"
23
+ end
24
+
25
+ # A cup can be peeked: it has mouse or not
26
+ predicate %w(.peeked .has_mouse .seen )
27
+ C.peeked.if C.has_mouse.assumed.or(:true).and C.seen.assumed
28
+
29
+ # A cup can be guessed: it has mouse or not
30
+ predicate %w(.guessed)
31
+ C.guessed.if C.has_mouse.assumed.or(:true)
32
+
33
+ end
34
+
35
+
36
+ class CupSet
37
+ extend Rubylog::Context
38
+
39
+ def initialize n
40
+ @cups = (1..n).map {|i| Cup.new i }
41
+ end
42
+
43
+ def each &block
44
+ @cups.each &block
45
+ end
46
+
47
+ def [] index
48
+ @cups[index]
49
+ end
50
+
51
+ # A set has neighbors if
52
+ predicate %w(.has_neighbors)
53
+ CS.has_neighbors.if [C,D].in{CS[0..-2].zip(CS[1..-1] || [])}.and C.has_mouse.and D.has_mouse
54
+
55
+ # A predicate definitely solves a set if there is no ambiguity
56
+ predicate_for Rubylog::Clause, %w(.definitely_solves())
57
+ T.definitely_solves(CS).if T.any(CS.has_neighbors).and(T.any(CS.has_neighbors.false)).false
58
+
59
+ # A trial consist of peeking some cups
60
+ predicate_for Rubylog::Clause, %w(.trial_for())
61
+ T.trial_for(CS).if T.is{C.in(CS).map{C.peeked.or :true}.inject(:true,&:and)}.and T
62
+
63
+ # A set is easy if can be definitely solved by a trial that has not seen all
64
+ # cups. A set is had if it cannot.
65
+ predicate %w(.easy() .hard)
66
+ CS.easy(Peeks).if any T.trial_for(CS).and(C.in(CS).all(C.seen).false).definitely_solves(CS).and(Peeks.is{D.in(CS).and(D.peeked).map{D}})
67
+ CS.hard.if CS.easy.false
68
+
69
+ end
70
+
71
+
72
+ N.in(0..4).each do
73
+ puts "#{N}:"
74
+ CS.is{CupSet.new(N)}.each do
75
+
76
+ C.in{CS}.each { p C }
77
+ T.trial_for(CS).each { p T }
78
+
79
+ easy = false
80
+ CS.easy(Peeks).each do
81
+ puts "easy: #{Peeks.inspect}"
82
+ easy = true
83
+ end
84
+ puts "hard" if not easy
85
+ end
86
+ puts
87
+ end
88
+
89
+
90
+
91
+
92
+
data/examples/mice2.rb ADDED
@@ -0,0 +1,19 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for Array, ".array(N) Peek.matches(Guess)"
5
+
6
+ [].peek!(0)
7
+ [K,*REST].mice(N[thats>0]).if K.in([0,1]).and N.sum_of(N1,1).and REST.mice(N1)
8
+
9
+ [].seen!([])
10
+ [0,*REST].seen([nil,*REST2]).if REST.seen(REST2)
11
+ [1,*REST].seen([A,*REST2]).if A.in([0,1]).and REST.seen(REST2)
12
+
13
+ [].guess!([])
14
+ [nil,*REST].guess([A,*REST2]).if A.in([0,1]).and REST.guess(REST2)
15
+ [0,*REST].guess([0,*REST2]).if A.in([0,1]).and REST.guess(REST2)
16
+ [1,*REST].guess([1,*REST2]).if A.in([0,1]).and REST.guess(REST2)
17
+
18
+ solve N.is(6).and any Peek.peek(N), all(Peek.seen(Seen), all(Guess.guess(Seen), Guess.has_neighbors.false).or(all(Guess.guess(Seen), Guess.has_neighbors)))
19
+
@@ -0,0 +1,32 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
3
+
4
+ rubylog do
5
+ predicate_for Integer, ".on(,)", ".attacks(,)", ".placed"
6
+ predicate ":arranged"
7
+
8
+ N=7
9
+
10
+ A.attacks(R,ANY_C).if A.on(R,ANY_C)
11
+ A.attacks(ANY_R,C).if A.on(ANY_R,C)
12
+ A.attacks(R2,C2).if A.on(R1,C1).and {R1-C1==R2-C2}
13
+ A.attacks(R2,C2).if A.on(R1,C1).and {R1+C1==R2+C2}
14
+
15
+ A.placed.if \
16
+ C.in(1..N).and(B.on(ANY,ANY).none(B.attacks(A,C))).and A.on(A,C).assumed
17
+
18
+ :arranged.if every A.in(1..N), A.placed
19
+
20
+ :arranged.solve do
21
+ L.in(1..N).each do
22
+ M.in(1..N).each do
23
+ print ANY.on?(L,M) ? "X" : "."
24
+ end
25
+ puts
26
+ end
27
+ puts
28
+ end
29
+
30
+
31
+ end
32
+
@@ -0,0 +1,14 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
3
+
4
+ class User
5
+ extend Rubylog::Context
6
+ predicate_for self, ".user", ".admin"
7
+
8
+ def initialize admin=false
9
+ self.user!
10
+ self.admin! if admin
11
+ end
12
+ end
13
+
14
+
@@ -0,0 +1,18 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for String, ".palindrome"
5
+
6
+ S[length: 0..1].palindrome!
7
+ S.palindrome.if S.is("#{A[length: 1]}#{B}#{A}").and B.palindrome
8
+
9
+ check "".palindrome
10
+ check "a".palindrome
11
+ check "aa".palindrome
12
+ check "aba".palindrome
13
+ check "abba".palindrome
14
+ check "ababa".palindrome
15
+ check "ab".palindrome.false
16
+ check "abb".palindrome.false
17
+ check "abbc".palindrome.false
18
+ check "ababab".palindrome.false
data/examples/parsing.rb CHANGED
@@ -1,10 +1,12 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
1
3
  require "readline"
2
4
 
3
- theory do
4
- functor_for String, :term, :expr, :atom
5
+ rubylog do
6
+ predicate_for String, ".term()", ".expr()", ".atom()"
5
7
 
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}+#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I+J}
9
+ "#{A}-#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I-J}
8
10
  A.expr(K).if A.term(K)
9
11
  "#{A}*#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I*J}
10
12
  "#{A}/#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I/J}
@@ -0,0 +1,12 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+ predicate_for Array, ".permutation()"
4
+
5
+ [].permutation! []
6
+ [*FRONT, A, *BACK].permutation([A,*REST]).if [*FRONT,*BACK].permutation(REST)
7
+
8
+ [1,2,3,4].permutation(P).each do
9
+ p P
10
+ end
11
+
12
+
@@ -0,0 +1,13 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for Kernel, ".hello()"
5
+
6
+ hello!(2)
7
+ hello(5).if { puts "Hello" }
8
+
9
+ hello?(5)
10
+
11
+ check hello(2)
12
+ check hello(4).false
13
+
@@ -0,0 +1,22 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for Integer, ".prime .odd .divides()"
5
+
6
+ A.divides(B).if { B%A == 0 }
7
+ A.odd.if 2.divides(A).false
8
+
9
+ 2.prime!
10
+ N[thats>2].prime.if N.odd.and none D[thats.odd?].in{3..Math.sqrt(N)}, D.divides(N)
11
+
12
+ check 1.prime.false
13
+ check 2.prime
14
+ check 3.prime
15
+ check 4.prime.false
16
+ check 5.prime
17
+ check 6.prime.false
18
+ check 7.prime
19
+ check 8.prime.false
20
+ check 9.prime.false
21
+ check 10.prime.false
22
+
@@ -1,17 +1,20 @@
1
1
  $:.unshift File.dirname(__FILE__)+"/../lib"
2
2
  require 'rubylog'
3
3
 
4
- Rubylog.theory "Try" do
5
- subject String
4
+ Try = Rubylog.create_context
5
+ Try.instance_eval do
6
+ predicate ":hello_world"
6
7
 
7
8
  def primitives.hello
8
9
  puts "Hello"
9
10
  yield
10
11
  end
11
12
 
12
- def primitives.hello x
13
- puts "Hello #{x.rubylog_deep_dereference}!"
14
- yield
13
+ class << primitives_for(String)
14
+ def hello x
15
+ puts "Hello #{x.rubylog_deep_dereference}!"
16
+ yield
17
+ end
15
18
  end
16
19
 
17
20
  :hello_world.if "World".hello
@@ -19,6 +22,5 @@ Rubylog.theory "Try" do
19
22
  end
20
23
 
21
24
 
22
- p Try.prove :hello
23
- p Try.prove :hello_world
24
- p Try.prove{X.is("World").and X.hello}
25
+ p Try.true? :hello
26
+ p Try.true? :hello_world
@@ -0,0 +1,14 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ predicate_for Integer, ".sieve .prime .nonprime .multiple_of(N,Limit)"
5
+
6
+ A.multiple_of(N,Limit).if I.in{(0..Limit/N)}.and A.is{N*I}
7
+
8
+ N.sieve.if X.in{2..N}.all X.nonprime.or(
9
+ proc{X.prime!}.and M.multiple_of(X,N).all{M.nonprime!}
10
+ )
11
+
12
+ 100.sieve.solve
13
+
14
+ p A.in(1..100).and(A.prime).map{A}
@@ -0,0 +1,4 @@
1
+ require "rubylog"
2
+ extend Rubylog::Context
3
+
4
+ solve S.is("Mary had a #{X} lamb.").and X.is("little").and { puts S }
@@ -0,0 +1,52 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
3
+
4
+ class Sudoku
5
+ def initialize
6
+ @rows = (1..9).map{(1..9).map{Rubylog::Variable.new}}
7
+ end
8
+
9
+ attr_reader :rows
10
+
11
+ def columns
12
+ @rows.transpose
13
+ end
14
+
15
+ def blocks
16
+ (0..2).map {|a| (0..2).map {|b| (0..2).map {|c| (0..2).map {|d|
17
+ @rows[a*3+c][b*3+d]
18
+ }}.flatten(1) }}.flatten(1)
19
+ end
20
+
21
+ extend Rubylog::Context
22
+
23
+ predicate_for Array, ".unique"
24
+ L.unique.unless L.is [*ANY, X, *ANY, X, *ANY]
25
+
26
+ predicate ".solved .good .shown .given(s)"
27
+ S.solved.if every L.in{S.rows}.and(F.in(L)), F.in(1..9)
28
+ S.good.if all(T.in{[S.rows, S.columns, S.blocks]}.and(L.in{T}), L.unique)
29
+
30
+ S.shown.if do
31
+ L.in{S.rows}.each do
32
+ p L
33
+ end
34
+ puts
35
+ true
36
+ end
37
+
38
+ _=ANY
39
+ solve S.is{Sudoku.new}.and lambda{S.rows}.is([
40
+ [5,_,_,_,2,4,7,_,_],
41
+ [_,_,2,_,_,_,8,_,_],
42
+ [1,_,_,7,_,3,9,_,2],
43
+ [_,_,8,_,7,2,_,4,9],
44
+ [_,2,_,9,8,_,_,7,_],
45
+ [7,9,_,_,_,_,_,8,_],
46
+ [_,_,_,_,3,_,5,_,6],
47
+ [9,6,_,_,1,_,3,_,_],
48
+ [_,5,_,6,9,_,_,1,_]
49
+ ]).and S.solved.and S.good.and S.shown rescue p $!
50
+ end
51
+
52
+
@@ -0,0 +1,19 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../lib"
2
+ require "rubylog"
3
+ extend Rubylog::Context
4
+
5
+ # no trace
6
+ solve S.is("Hello #{X}!").and X.is("no Trace") do puts S end
7
+
8
+ # tracing with on/off
9
+ Rubylog.trace!
10
+ solve S.is("Hello #{X}!").and X.is("Trace") do puts S end
11
+ Rubylog.trace!(false)
12
+
13
+ # no trace again
14
+ solve S.is("Hello #{X}!").and X.is("no Trace again") do puts S end
15
+
16
+ # tracing with block
17
+ Rubylog.trace do
18
+ solve S.is("Hello #{X}!").and X.is("Trace with block") do puts S end
19
+ end
@@ -0,0 +1,29 @@
1
+ require "rspec"
2
+ require "rubylog"
3
+
4
+ # This module is included in RSpecExampleGroup's with rubylog:true metadata.
5
+ #
6
+ module Rubylog::RSpecExampleGroup
7
+ def self.included example_group
8
+ # Make it a context
9
+ example_group.extend Rubylog::Context
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |c|
14
+
15
+ # enable use of Rubylog in example groups
16
+ c.include Rubylog::RSpecExampleGroup, :rubylog => true
17
+
18
+ # enable use of Rubylog in examples
19
+ c.before do
20
+ # when :rubylog=>true is given
21
+ if self.class.metadata[:rubylog]
22
+ # create the context from the example
23
+ # this initializes the context
24
+ Rubylog.create_context self
25
+ end
26
+ end
27
+ end
28
+
29
+