Skip to content

Instantly share code, notes, and snippets.

@litonico
Last active June 6, 2016 23:30
Show Gist options
  • Save litonico/7fd3061ad15fb959ac3c to your computer and use it in GitHub Desktop.
Save litonico/7fd3061ad15fb959ac3c to your computer and use it in GitHub Desktop.
McCarthy's `amb` operator using exceptions
require 'continuation'
# Example implementation using call/cc,
# stolen in part from randomhacks.net blog
class CallCCAmb
def initialize
@backtrack_points = []
end
def backtrack
if @backtrack_points.empty?
raise "Can't backtrack"
else
@backtrack_points.pop.call
end
end
def amb *choices
backtrack if choices.empty?
callcc {|cc|
@backtrack_points.push cc
return choices[0]
}
amb(*choices[1...choices.length])
end
def example
a = amb(1, 2, 3)
b = amb(2, 3, 4)
backtrack unless a*b == 6
puts a, b
end
end
puts "Call/cc example: find numbers that * to 6:"
CallCCAmb.new.example
puts "\n"
class ExceptionAmb
Backtrack = Class.new(StandardError)
def initialize
@answers = []
end
def backtrack
raise Backtrack
end
def amb *choices, &block
backtrack if choices.empty?
block.call choices[0]
# We've made it without backtracking!
@answers << choices[0]
rescue Backtrack
backtrack if choices.empty? # Backtrack *up a level*
amb(*choices[1..choices.length], &block) # Try the rest
end
def example
amb(1, 2, 3) do |a|
amb(2, 3, 4) do |b|
backtrack unless a*b == 6
end
end
puts @answers
end
end
puts "Exception-backtracking example: find numbers that * to 6:"
ExceptionAmb.new.example
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment