Leopold Toetsch <[EMAIL PROTECTED]> writes:

> Piers Cawley <[EMAIL PROTECTED]> wrote:
>
>> Remember how Leo wanted an example of how continuations were used?
>
> Great example - I don't understand how it wotks though :) - but I
> understand, why the PIR code might fail:

Okay, I'll try and explain it.

Every time you call choose, it grabs the current continuation (the
place that this particular call to choose will return to) and stuffs it
in a lexical variable and saves the current fail closure as
'old_fail'. Then it creates a closure called try and sticks that in the
lexical pad too. Finally, it calls try with the list of possible
choices.

Try checks to see if their are any choices left. If there are it pulls
the first item off the list of choices for a return value, and sets up
'fail' so that, when invoked it will simply call 'try' with the
remainder of the choices. Then it uses the saved continuation to return
the first item to the point where choose was called from. 

If there *aren't* any choices, it sets fail to be the 'fail' that is
saved in its 'old_fail' and simply calls that. 


So, what does that mean when you have:

    x = _choose(array1) # cont1
    y = _choose(array2) # cont2, cont3

    $I0 = x
    $I1 = y
    $I2 = x * y

    if $I2 == 15 goto success
    $P0 = find_lex("fail")
    $P0() # Why can't we do this? Does $P0.() work any better?
    branch the_end
  success:
    print x
    print " * "
    print y
    print " == 15\n"
  the_end:
    ...


Calling the first choose sets up a try (call it try1), saves 'fail' in
that try's 'old_fail', sets up the new fail to call 'try1(3,5)' and returns
1.

The second choose call sets up a new try (try2), saves the fail that would
call 'try1(3,5)' in its old_fail, sets up the new fail to call 'try2(5,9)' and
returns 1

Obviously, 1 * 1 doesn't equal 15, so fail gets called, which in turn
calls 'try2(5,9)' which sets fail up to call 'try2(9)' and returns 5 to
cont2

y is now 5, but 1 * 5 still doesn't equal 15, so fail calls try2(9),
which sets up fail to call try2() and returns 9 to cont2

9 * 1 doesn't equal 15 either, so we call fail, which calls try2(). 

try2() doesn't have any choices left, so it reinstates its old_fail and
invokes that, which calls try1(3,5).

try1(3,5) sets up fail to call try1(5) and returns 3 to cont1.

So now we call _choose(1,5,9) again, which makes a new try (try3),
which sets fail up to call try3(5,9) and returns 1 to cont3.

Guess what? 1 * 3 *still* doesn't equal 15, so we fail again, which
calls try3(5,9), which returns 5 to cont3 and does what we expect to
the current fail. And finally, 3 * 5 equals 15, so we announce the glad
tidings and continue on our merry way. 

If I weren't such a lazy programmer I'd have implemented a
'reset_searchs' to set fail back to the original 'This search didn't
work!' value, allowing the saved failure 'continuations' to get garbage
collected, and setting things up for new choices.

See, I told you it was easy.

Reply via email to