Module: Porolog::Predicate::Builtin
- Defined in:
- lib/porolog/predicate/builtin.rb
Overview
The Porolog::Predicate::Builtin module is a collection of the implementations of the builtin predicates. It is possible to define custom builtin predicates. Each builtin requires a goal and a block, and should return the result of
block.call(goal) || false
if the predicate is deemed successful; otherwise, it should return false.
Instance Method Summary collapse
-
#append(goal, block, front, back, front_back) ⇒ Boolean
Corresponds to the standard Prolog append predicate.
-
#atom(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog atom predicate.
-
#atomic(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog atomic predicate.
-
#between(goal, block, variable, lower, upper) ⇒ Boolean
Does not correspond to a standard Prolog predicate.
-
#eq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog == predicate.
-
#gtr(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog > predicate.
-
#gtreq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog >= predicate.
-
#integer(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog integer predicate.
-
#is(goal, block, variable, *args, &is_block) ⇒ Boolean
Corresponds to the standard Prolog is predicate.
-
#is_eq(goal, block, x, y) ⇒ Boolean
Corresponds to a synthesis of the standard Prolog == and is predicates.
-
#is_noteq(goal, block, variable, all_values, *exclusions) ⇒ Boolean
This does not really correspond to a standard Prolog predicate.
-
#length(goal, block, list, length) ⇒ Boolean
Corresponds to the standard Prolog length predicate.
-
#less(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog < predicate.
-
#lesseq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog <= predicate.
-
#member(goal, block, element, list, limit = 100) ⇒ Boolean
Corresponds to the standard Prolog member predicate.
-
#nl(goal, block) ⇒ Boolean
Corresponds to the standard Prolog nl predicate.
-
#nonvar(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog nonvar predicate.
-
#noteq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog != predicate.
-
#permutation(goal, block, list1, list2) ⇒ Boolean
Corresponds to the standard Prolog permutation predicate.
-
#reverse(goal, block, list1, list2) ⇒ Boolean
Corresponds to the standard Prolog reverse predicate.
-
#ruby(goal, block, *args, &ruby_block) ⇒ Boolean
Allows a plain Ruby block to be executed as a goal.
-
#var(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog var predicate.
-
#write(goal, block, *args) ⇒ Boolean
Corresponds to the standard Prolog print predicate.
-
#writenl(goal, block, *args) ⇒ Boolean
Corresponds to the standard Prolog print and nl predicate.
Instance Method Details
#append(goal, block, front, back, front_back) ⇒ Boolean
Corresponds to the standard Prolog append predicate. This implements the usual operation of member but also provides the ability instantiate uninstantiated arguments as an instnatiation of the concatenation of the first two arguments. Use:
append([1,2,3], [4,5,6], [1,2,3,4,5,6])
append([1,2,3], [4,5,6], :C)
append([1,2,3], :B, [1,2,3,4,5,6])
append(:A, [4,5,6], [1,2,3,4,5,6])
append(:A, :B, [1,2,3,4,5,6])
append([1,2,3], :B, :C)
append(:A, [4,5,6], :C)
append(:A, :B, :C)
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
# File 'lib/porolog/predicate/builtin.rb', line 594 def append(goal, block, front, back, front_back) front = front.value.value back = back.value.value front_back = front_back.value.value case [front.type, back.type, front_back.type] when [:array, :array, :array] satisfied = false if front.length + back.length == front_back.length unifications = Porolog::unify(front + back, front_back, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) end satisfied when [:array, :array, :variable] satisfied = false unifications = Porolog::unify(front + back, front_back, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied when [:array, :variable, :array] satisfied = false if front.length <= front_back.length expected_front = front_back[0...front.length] expected_back = front_back[front.length..-1] unifications = Porolog::unify(front, expected_front, goal) unifications += Porolog::unify(back, expected_back, goal) if unifications instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) end satisfied when [:variable, :array, :array] satisfied = false if back.length <= front_back.length expected_front = front_back[0...-back.length] expected_back = front_back[-back.length..-1] unifications = Porolog::unify(front, expected_front, goal) unifications += Porolog::unify(back, expected_back, goal) if unifications instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) end satisfied when [:variable, :variable, :array] satisfied = false (front_back.length + 1).times do |i| expected_front = front_back[0...i] expected_back = front_back[i..-1] unifications = Porolog::unify(front, expected_front, goal) unifications += Porolog::unify(back, expected_back, goal) if unifications instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) return satisfied if goal.terminated? end satisfied when [:array, :variable, :variable] satisfied = false unifications = Porolog::unify(front / back, front_back, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied when [:variable, :array, :variable] satisfied = false instantiation_head = front_back.instantiate(front, nil, :flathead) instantiation_tail = front_back.instantiate(back, nil, :flattail) instantiations = [instantiation_head, instantiation_tail].compact instantiations = nil if instantiations.empty? instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied when [:variable, :variable, :variable] satisfied = false instantiation_head = front_back.instantiate(front, nil, :flathead) instantiation_tail = front_back.instantiate(back, nil, :flattail) instantiations = [instantiation_head, instantiation_tail].compact instantiations = nil if instantiations.empty? instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied else false end end |
#atom(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog atom predicate. It is satisfied if the argument is a String. Use:
atom(:X)
132 133 134 |
# File 'lib/porolog/predicate/builtin.rb', line 132 def atom(goal, block, variable) variable.value.value.is_a?(String) && block.call(goal) || false end |
#atomic(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog atomic predicate. It is satisfied if the argument is a String or an Integer. Use:
atomic(:X)
144 145 146 |
# File 'lib/porolog/predicate/builtin.rb', line 144 def atomic(goal, block, variable) variable.value.value.type == :atomic && block.call(goal) || false end |
#between(goal, block, variable, lower, upper) ⇒ Boolean
Does not correspond to a standard Prolog predicate. This is a convenience Predicate to allow efficient control of iteration as well as range comparison. Use:
between(5, 0, 9)
between(:N, 0, 9)
between(:N, :Upper, :Lower)
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
# File 'lib/porolog/predicate/builtin.rb', line 459 def between(goal, block, variable, lower, upper) variable = variable.value.value lower = lower.value.value upper = upper.value.value case [variable.type, lower.type, upper.type] when [:atomic, :atomic, :atomic] (lower..upper) === variable && block.call(goal) || false when [:atomic, :variable, :variable] satisfied = false lower_instantiation = lower.instantiate(variable) upper_instantiation = lower_instantiation && upper.instantiate(variable) upper_instantiation && block.call(goal) && (satisfied = true) upper_instantiation&.remove lower_instantiation&.remove satisfied when [:atomic, :atomic, :variable] satisfied = false if variable >= lower upper_instantiation = upper.instantiate(variable) upper_instantiation && block.call(goal) && (satisfied = true) upper_instantiation&.remove end satisfied when [:atomic, :variable, :atomic] satisfied = false if variable <= upper lower_instantiation = lower.instantiate(variable) lower_instantiation && block.call(goal) && (satisfied = true) lower_instantiation&.remove end satisfied when [:variable, :atomic, :atomic] satisfied = false (lower..upper).each do |i| instantiation = variable.instantiate(i) instantiation && block.call(goal) && (satisfied = true) || false instantiation&.remove return satisfied if goal.terminated? end satisfied else false end end |
#eq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog == predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) that are equal, or
-
it is provided with two uninstantiaed Variables that are bound to each other.
Variables are not instantiated; however, if they are uninstantiated, they are temporarily instantiated to a unique value to see if they are bound in some way. Use:
eq(:X, :Y)
eq(:name, ['Sam', 'Smith'])
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/porolog/predicate/builtin.rb', line 174 def eq(goal, block, x, y) x = x.value.value y = y.value.value case [x.type, y.type] when [:variable, :variable] equal = false temporary_instantiation = x.instantiate UNIQUE_VALUE if temporary_instantiation equal = y.value.value == UNIQUE_VALUE temporary_instantiation.remove end equal else x == y end && block.call(goal) || false end |
#gtr(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog > predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) where the first is greater than the second.
Variables are not instantiated. Use:
gtr(:X, :Y)
gtr(:X, 3)
gtr(9, :Y)
gtr(:name, 'max')
331 332 333 334 335 336 337 338 339 340 |
# File 'lib/porolog/predicate/builtin.rb', line 331 def gtr(goal, block, x, y) x = x.value.value y = y.value.value if [x.type, y.type].include?(:variable) false else x > y end && block.call(goal) || false end |
#gtreq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog >= predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) where the first is greater than or equal to the second, or
-
it is provided with two uninstantiaed Variables that are bound to each other.
Variables are not instantiated (except temporarily to test if they are bound). Use:
gtreq(:X, :Y)
gtreq(:X, 3)
gtreq(9, :Y)
gtreq(:name, 'max')
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/porolog/predicate/builtin.rb', line 394 def gtreq(goal, block, x, y) x = x.value.value y = y.value.value case [x.type, y.type] when [:variable, :variable] equal = false temporary_instantiation = x.instantiate UNIQUE_VALUE if temporary_instantiation equal = y.value.value == UNIQUE_VALUE temporary_instantiation.remove end equal else if [x.type, y.type].include?(:variable) false else x >= y end end && block.call(goal) || false end |
#integer(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog integer predicate. It is satisfied if the argument is an Integer. Use:
integer(:X)
156 157 158 |
# File 'lib/porolog/predicate/builtin.rb', line 156 def integer(goal, block, variable) variable.value.value.is_a?(Integer) && block.call(goal) || false end |
#is(goal, block, variable, *args, &is_block) ⇒ Boolean
Corresponds to the standard Prolog is predicate. It instantiates a Variable with the result of the provided block. Use:
is(:Y, :X) {|x| x + 1 }
is(:name, :first, :last) {|first, last| [first, last] }
is(:name, :first, :last) {|first, last| "#{first} #{last}" }
92 93 94 95 96 97 98 |
# File 'lib/porolog/predicate/builtin.rb', line 92 def is(goal, block, variable, *args, &is_block) raise NonVariableError, "#{variable.inspect} is not a variable" unless variable.type == :variable result = is_block.call(*args.map(&:value).map(&:value)) result && !!variable.instantiate(result) && block.call(goal) || false end |
#is_eq(goal, block, x, y) ⇒ Boolean
Corresponds to a synthesis of the standard Prolog == and is predicates. The left hand side (i.e. the first parameter) must be a variable. It compares equality if the left hand side is instantiated; otherwise, it instantiates the left hand side to the right hand side. It is satisfied if:
-
the values are equal, or
-
the variable can successfully be instantiated to the right hand side.
Use:
is_eq(:X, :Y)
is_eq(:name, ['Sam', 'Smith'])
207 208 209 210 211 212 |
# File 'lib/porolog/predicate/builtin.rb', line 207 def is_eq(goal, block, x, y) return false unless x.type == :variable return block.call(goal) if x.value.value == y.value.value !!x.instantiate(y) && block.call(goal) || false end |
#is_noteq(goal, block, variable, all_values, *exclusions) ⇒ Boolean
This does not really correspond to a standard Prolog predicate. It implements a basic constraint mechanism. The Variable is instantiated (if possible) to all possible values provide except for all exclusions. Further, the exclusions are checked for collective uniqueness. Use:
is_noteq(:digit, (0..9).to_a, :second_digit, :fifth_digit)
277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/porolog/predicate/builtin.rb', line 277 def is_noteq(goal, block, variable, all_values, *exclusions) return false unless variable.type == :variable all_values = all_values.map(&:value).map(&:value) exclusions = exclusions.map(&:value).map(&:value) possible_values = goal[Porolog::anonymous] if exclusions.uniq.size == exclusions.size !!possible_values.instantiate(all_values - exclusions) && Predicate.call_builtin(:member, goal, block, variable, possible_values) || false else false end end |
#length(goal, block, list, length) ⇒ Boolean
Corresponds to the standard Prolog length predicate. It is satisfied if:
-
it is provided with an Array and an Integer where the Integer corresponds to the length of the Array,
-
it is provided with an Array and a Variable and the Variable is successfully instantiated to the length of the Array, or
-
it is provided with a Variable and an Integer where the Variable is successfully instantiated to an of anonymous variables.
Use:
length([1,2,3,4], 4)
length([1,2,3,4], :Length)
length(:L, 4)
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/porolog/predicate/builtin.rb', line 430 def length(goal, block, list, length) list = list.value.value length = length.value.value case [list.type, length.type] when [:array, :atomic] list.length == length when [:variable, :atomic] list.instantiate(Array.new(length){goal[Porolog::anonymous]}) when [:array, :variable] length.instantiate(list.length) else false end && block.call(goal) || false end |
#less(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog < predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) where the first is less than the second.
Variables are not instantiated. Use:
less(:X, :Y)
less(:X, 3)
less(9, :Y)
less(:name, 'max')
306 307 308 309 310 311 312 313 314 315 |
# File 'lib/porolog/predicate/builtin.rb', line 306 def less(goal, block, x, y) x = x.value.value y = y.value.value if [x.type, y.type].include?(:variable) false else x < y end && block.call(goal) || false end |
#lesseq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog <= predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) where the first is less than or equal to the second, or
-
it is provided with two uninstantiaed Variables that are bound to each other.
Variables are not instantiated (except temporarily to test if they are bound). Use:
lesseq(:X, :Y)
lesseq(:X, 3)
lesseq(9, :Y)
lesseq(:name, 'max')
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/porolog/predicate/builtin.rb', line 357 def lesseq(goal, block, x, y) x = x.value.value y = y.value.value case [x.type, y.type] when [:variable, :variable] equal = false temporary_instantiation = x.instantiate UNIQUE_VALUE if temporary_instantiation equal = y.value.value == UNIQUE_VALUE temporary_instantiation.remove end equal else if [x.type, y.type].include?(:variable) false else x <= y end end && block.call(goal) || false end |
#member(goal, block, element, list, limit = 100) ⇒ Boolean
Corresponds to the standard Prolog member predicate. This implements the usual operation of member but also provides the ability to generate lists that contain the provided element, even if the element is an uninstantiated variable. Use:
member(3, [1,2,3,4,5])
member(['Chris','Smith'], [['Foo','Bar'],['Boo','Far'],['Chris','Smith']])
member(:X, [1,2,3,4,5])
member(:X, :Y)
member(:X, :Y, 5)
member(3, :Y, 10)
member(['Chris','Smith'], :Names, 16)
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
# File 'lib/porolog/predicate/builtin.rb', line 528 def member(goal, block, element, list, limit = 100) element_value = element.value.value list = list.value.value case [element_value.type, list.type] when [:atomic, :array], [:array, :array] satisfied = false list.each do |i| unifications = Porolog::unify(element_value, i, goal) if unifications instantiations = Porolog::instantiate_unifications(unifications) if instantiations block.call(goal) && (satisfied = true) instantiations.each(&:remove) end end return satisfied if goal.terminated? end satisfied when [:variable, :array] satisfied = false list.each do |i| instantiation = element_value.instantiate(i) instantiation && block.call(goal) && (satisfied = true) instantiation&.remove return satisfied if goal.terminated? satisfied = true end satisfied when [:variable, :variable], [:atomic, :variable], [:array, :variable] satisfied = false limit.times do |i| instantiation = list.instantiate([*Array.new(i){goal[Porolog::anonymous]}, element, Porolog::UNKNOWN_TAIL]) instantiation && block.call(goal) && (satisfied = true) instantiation&.remove return satisfied if goal.terminated? end satisfied else false end end |
#nl(goal, block) ⇒ Boolean
Corresponds to the standard Prolog nl predicate. It outputs a newline. Use:
nl
75 76 77 78 |
# File 'lib/porolog/predicate/builtin.rb', line 75 def nl(goal, block) $stdout.puts block.call(goal) || false end |
#nonvar(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog nonvar predicate. It is satisfied if the argument is not an uninstantiated variable. Use:
nonvar(:X)
120 121 122 |
# File 'lib/porolog/predicate/builtin.rb', line 120 def nonvar(goal, block, variable) variable.value.value.type != :variable && block.call(goal) || false end |
#noteq(goal, block, x, y) ⇒ Boolean
Corresponds to the standard Prolog != predicate. It is satisfied if:
-
it is provided with two values (or instantiated Variables) that are unequal, or
-
it is provided with two uninstantiaed Variables that are not bound to each other.
Variables are not instantiated; however, if they are uninstantiated, they are temporarily instantiated to a unique value to see if they are bound in some way. Use:
noteq(:X, :Y)
noteq(:name, ['Sam', 'Smith'])
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/porolog/predicate/builtin.rb', line 246 def noteq(goal, block, x, y) x = x.value.value y = y.value.value case [x.type, y.type] when [:variable, :variable] equal = false temporary_instantiation = x.instantiate UNIQUE_VALUE if temporary_instantiation equal = y.value.value == x.value.value temporary_instantiation.remove end !equal else x != y end && block.call(goal) || false end |
#permutation(goal, block, list1, list2) ⇒ Boolean
Corresponds to the standard Prolog permutation predicate. It not only returns whether one list is a permutation of the other but also can generate permutations. Use:
permutation([3,1,2,4], [1,2,3,4])
permutation([3,:A,2,4], [1,2,3,4])
permutation([3,1,2,4], [1,2,:C,4])
permutation([3,1,:B,4], [1,2,:C,4])
permutation([3,1,2,4], :Q)
permutation(:P, [1,2,3,4])
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
# File 'lib/porolog/predicate/builtin.rb', line 709 def permutation(goal, block, list1, list2) # TODO: Detect and deal with tails # E.g. permutation([:H]/:T, [1,...]) list1 = list1.value.value list2 = list2.value.value case [list1.type, list2.type] when [:array, :array] satisfied = false case [list1.variables.empty?, list2.variables.empty?] when [true, true] list1 = list1.sort_by(&:inspect) list2 = list2.sort_by(&:inspect) unifications = Porolog::unify(list1, list2, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) when [false, true], [false, false] list2.permutation do |p| unifications = Porolog::unify(list1, p, goal) instantiations = nil instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) return satisfied if goal.terminated? end when [true, false] list1.permutation do |p| unifications = Porolog::unify(list2, p, goal) instantiations = nil instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) return satisfied if goal.terminated? end end satisfied when [:array, :variable] satisfied = false list1.permutation do |p| unifications = Porolog::unify(p, list2, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) return satisfied if goal.terminated? end satisfied when [:variable, :array] satisfied = false list2.permutation do |p| unifications = Porolog::unify(list1, p, goal) instantiations = nil instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) return satisfied if goal.terminated? end satisfied else false end end |
#reverse(goal, block, list1, list2) ⇒ Boolean
Corresponds to the standard Prolog reverse predicate. It returns whether the lists are a reversal of each other, or otherwise generates a reversed list. Use:
reverse([1,2,3,4], [4,3,2,1])
reverse([1,:A,3,4], [4,3,2,1])
reverse([1,2,3,4], [4,:B,2,1])
reverse([1,:A,3,4], [4,:B,2,1])
reverse(:L, [4,3,2,1])
reverse([1,2,3,4], :L)
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 |
# File 'lib/porolog/predicate/builtin.rb', line 793 def reverse(goal, block, list1, list2) # TODO: Detect and deal with tails # E.g. reverse([:H]/:T, [1,...]) list1 = list1.value.value list2 = list2.value.value case [list1.type, list2.type] when [:array, :array], [:variable, :array] satisfied = false unifications = Porolog::unify(list1, list2.reverse, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied when [:array, :variable] satisfied = false unifications = Porolog::unify(list1.reverse, list2, goal) instantiations = Porolog::instantiate_unifications(unifications) if unifications instantiations && block.call(goal) && (satisfied = true) instantiations&.each(&:remove) satisfied else false end end |
#ruby(goal, block, *args, &ruby_block) ⇒ Boolean
Allows a plain Ruby block to be executed as a goal. It is assumed to be successful unless evaluates to :fail . Use:
ruby(:X, :Y, :Z) {|x, y, z| csv << [x, y, z] }
ruby { $stdout.print '.' }
ruby {
$stdout.puts 'Forcing backtracking ...'
:fail
}
228 229 230 |
# File 'lib/porolog/predicate/builtin.rb', line 228 def ruby(goal, block, *args, &ruby_block) (ruby_block.call(goal, *args.map(&:value).map(&:value)) != :fail) && block.call(goal) || false end |
#var(goal, block, variable) ⇒ Boolean
Corresponds to the standard Prolog var predicate. It is satisfied if the argument is an uninstantiated variable. Use:
var(:X)
108 109 110 |
# File 'lib/porolog/predicate/builtin.rb', line 108 def var(goal, block, variable) variable.value.value.type == :variable && block.call(goal) || false end |
#write(goal, block, *args) ⇒ Boolean
Corresponds to the standard Prolog print predicate. ‘print` could not be used because of the clash with the Ruby method. It outputs all arguments. If an argument is a variable, then if it is instantiated, its value is output; otherwise its name is output. If the value is an Array, its inspect is output instead. Use:
write('X = ', :X, ', Y = ', :Y, "\n")
33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/porolog/predicate/builtin.rb', line 33 def write(goal, block, *args) args = args.map(&:value).map(&:value) args = args.map{|arg| arg.is_a?(Array) ? arg.inspect : arg } args = args.map{|arg| arg.type == :variable ? arg.to_sym.inspect : arg } $stdout.print args.join block.call(goal) || false end |
#writenl(goal, block, *args) ⇒ Boolean
Corresponds to the standard Prolog print and nl predicate. ‘print` could not be used because of the clash with the Ruby method. It outputs all arguments and a new line. If an argument is a variable, then if it is instantiated, its value is output; otherwise its name is output. If the value is an Array, its inspect is output instead. Use:
writenl('X = ', :X, ', Y = ', :Y)
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/porolog/predicate/builtin.rb', line 56 def writenl(goal, block, *args) args = args.map(&:value).map(&:value) args = args.map{|arg| arg.is_a?(Array) ? arg.inspect : arg } args = args.map{|arg| arg.type == :variable ? arg.to_sym.inspect : arg } $stdout.puts args.join block.call(goal) || false end |