After a bit of thought I realize this problem was a poster child
application for languages like Prolog or Mercury.
But I know I'm not going to have to time to learn them.
But ruby is pretty flexible...
Anybody have any Prolog alike goal finding / backtracking type ruby
module available? (Couldn't spot any on RAA or rubyforge.)
John Carter                             Phone : (64)(3) 358 6639
Tait Electronics                        Fax   : (64)(3) 359 4632
PO Box 1645 Christchurch                Email : john....@tait.co.nz
New Zealand
A Million Monkeys can inflict worse things than just Shakespeare on
your system.
I'm interessted in a framework for backtracking in ruby, too.
I think, using the Regexp Class an their methods will help, solving this
problem in a general way.
Fred from Wuppertal, Germany
> Anybody have any Prolog alike goal finding / backtracking type ruby
> module available? (Couldn't spot any on RAA or rubyforge.)
This isn't really prolog alike, but it's a nice simple backtracking
facility.  To test it, try this:
    amb = Amb.new
    x = amb.one_of(1..10)
    y = amb.one_of(1..10)
    amb.assert(x + y == 7)
    amb.assert(x - y == 1)
    puts [x,y]  #=> 4, 3
Or, say, this:
    if amb.maybe
        x = 1
        y = 3
    else
        x = 7
        y = 10
    end
    
    amb.assert(x > 1)
    puts y #=> 10
    
    amb.assert(y < 10) #=> error
To read more about it, search for "john mccarthy's amb" or see
http://gd.tuwien.ac.at/languages/scheme/tutorial-dsitaram/t-y-scheme-Z-H-15.html
Cheers,
Avi
-----------------
#amb.rb
#Avi Bryant, Nov. 2003
class Amb
    def initialize
        @failureContinuation = proc{raise "Amb goal tree exhausted"}
    end
    
    def fail
        @failureContinuation.call(nil)
    end
    
    def assert(bool)
        fail unless bool
    end
    
    def choose(procArray)
        kPrev = @failureContinuation
        callcc do |kEntry|
            procArray.each do |p|
                callcc do |kNext|
                    @failureContinuation = proc do |v|
                        @failureContinuation = kPrev
                        kNext.call(v)
                    end
                    kEntry.call(p.call)
                end
            end
            kPrev.call(nil)
        end
    end
    
    def one_of(enumerable)
        choose(enumerable.collect{|ea| proc{ea}})
    end
    def maybe
        one_of([true, false])
    end
end