Remember how Leo wanted an example of how continuations were used?

Well, I ported the following Scheme code to PIR. (The PIR is appended
to this message...

  ;;; Indicate that the computation has failed, and that the program
  ;;; should try another path.  We rebind this variable as needed.
  (define fail
    (lambda () (error "Program failed")))
  
  ;;; Choose an arbitrary value and return it, with backtracking.
  ;;; You are not expected to understand this.
  (define (choose . all-choices)
    (let ((old-fail fail))
      (call-with-current-continuation
       (lambda (continuation)
         (define (try choices)
           (if (null? choices)
               (begin
                 (set! fail old-fail)
                 (fail))
               (begin
                 (set! fail
                      (lambda () (continuation (try (cdr choices)))))
                 (car choices))))
         (try all-choices)))))
  
  ;;; Find two numbers with a product of 15.
  (let ((x (choose 1 3 5))
        (y (choose 1 5 9)))
    (for-each display `("Trying " ,x " and " ,y #\newline))
    (unless (= (* x y) 15)
      (fail))
    (for-each display `("Found " ,x " * " ,y " = 15" #\newline)))

Which (as anyone can plainly see) implements a non deterministic
search (and something like it could come in handy when implementing
Perl 6 Junctions). 

I think I've tweaked a bug in the GC somewhere because 'parrot -t
choose.imc' and 'parrot -tG choose.imc' fail in different places.

Also, I thought Leo's patches to the stacks meant that RetContinuations
had been done away with, but the trace output implies otherwise, and it
may be that the code is failing because of this difference. The call to
fail *should* return to just after the second call to choose by
invoking the lexically held continuation, but this isn't what happens

Rejigging IMCC to use Continuations instead of RetContinuations (using
a simple minded search & replace) makes things fall over with a Bus
Error.

Enjoy.


.sub main
     .local pmc arr1
     .local pmc arr2
     .local pmc x
     .local pmc y
     .local pmc choose
     .local pmc fail
     new_pad 0
     $P0 = new PerlArray
     store_lex 0, "*paths*", $P0
     $P0 = new PerlString
     $P0 = "@"
     store_lex 0, "failsym", $P0
     store_lex 0, "choose", $P0
     store_lex 0, "fail", $P0
     newsub choose, .Closure, _choose
     store_lex "choose", choose
     newsub fail, .Closure, _fail
     store_lex "fail", fail
     arr1 = new PerlArray
     arr1[0] = 1
     arr1[1] = 3
     arr1[2] = 5
     arr2 = new PerlArray
     arr2[0] = 1
     arr2[1] = 5
     arr2[2] = 9
     
     x = choose(arr1)
     print "Chosen "
     print x
     print " from arr1\n"
     y = choose(arr2)
     print "Chosen "
     print y
     print " from arr2\n"
     $I1 = x
     $I2 = y
     $I0 = $I1 * $I2
     if $I0 == 15 goto success
     fail = find_lex "fail"
     fail()
     print "Shouldn't get here without a failure report\n"
     branch the_end
success:
     print x
     print " * "
     print y
     print " == 15!\n"
the_end:
     end
.end
     


.sub _choose
     .param PerlArray choices
     .local pmc our_try
     print "Choose: "
     $S0 = typeof choices
     print $S0
     print "\n"
     new_pad 1
     find_lex $P0, "fail"
     store_lex 1, "old_fail", $P0
     store_lex 1, "cc", P1
     newsub our_try, .Closure, _try
     store_lex 1, "try", our_try
     $P2 = our_try(choices)
     .pcc_begin_return
     .return $P2
     .pcc_end_return
.end

.sub _try
     .param PerlArray choices
     print "In try\n"
     $S0 = typeof choices
     print $S0
     print "\n"
     new_pad 2
     clone $P0, choices
     store_lex 2, "choices", $P0
     if choices goto have_choices
     $P1 = find_lex "old_fail"
     store_lex "fail", $P1
     invokecc $P1
have_choices:
     newsub $P2, .Closure, new_fail
     store_lex "fail", $P2
     $P3 = find_lex "choices"
     $S0 = typeof $P3
     print $S0
     print "\n"
     shift $P4, $P3

     .pcc_begin_return
     .return $P4
     .pcc_end_return

new_fail:
     .local pmc our_try
     .local pmc our_cc
     save P1
     print "In new_fail\n"
     our_cc = find_lex "cc"
     our_try = find_lex "try"
     $P2 = find_lex "choices"
     $S0 = typeof $P2
     print $S0
     print "\n"
     $P3 = our_try($P2)
     restore P1
     unless our_cc == P1 goto do_return
     print "Something's very wrong with continuations!\n"
do_return:
     our_cc($P3)
.end
    

.sub _fail
     print "Program failed\n"
     .pcc_begin_return
     .pcc_end_return
.end

     
     

Reply via email to