Forum: Ruby Continuations

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Paul w F. (Guest)
on 2009-02-03 00:11
Please help. I'm totally confused by following behaviour with regard to
continuations (Ruby 1.8.7) My goal was to simply jump between two loops,
which worked fine. But I do not really understand this behaviour:


def loller(id, num, that)
    loop do
        puts id.to_s + " " + num.to_s
        num += 1
        sleep(0.5)

        # why do i need to update 'that' here, but not 'well' in the
while loop??
        # callcc { |here| that.call(here) }, w/o assignment doesn't work
here
        that = callcc { |here| that.call(here) }

        # any subsequent calls to 'well' (well.call) should return to
THIS POINT
        # with num == 35
        # since I never reassign the continuation referenced by 'well'


    end
end


i = 0
well = callcc { |c| loller(1,34,c)  }

while true

    # why don't I need: well = callcc { |here| well.call(here) }
    # callcc { |here| well.call(here) }, w/o assignment works here!!!
    callcc { |here| well.call(here) }
    puts "back to root " + i.to_s
    i += 1

end



This program increases a simple counter in each loop, and prints it.
However, I do not understand why this works, since I am not reassigning
the continuation returned by the loop in function "loller". The call
made from the while-loop was looking like this to begin with:

well = callcc { |here| well.call(here) }

Which gives the same result, even when i remove the assignment. That
means the 'well' variable still references the original continuation
i.e. value of 'num' inside loller should always be the same as in
original continuation? Should I remove the analogous assignment from the
loop in "loller" then as expected i never get "back to root" printout,
since then "loller" always returns to the point after the original
assignment, and thst is just before the while loop.

Anybody who understand this, please explain. Big thanks in advance.

/Paul W Florczykowski
Patrick R. (Guest)
on 2009-02-03 03:50
(Received via mailing list)
Responding to Paul w Florczykowski:

[Disclaimer: I'm certainly not a pro on continuations, but I'll just
give it a try. Please bear with me.]

>         # any subsequent calls to 'well' (well.call) should return to THIS POINT
>     # callcc { |here| well.call(here) }, w/o assignment works here!!!
>     callcc { |here| well.call(here) } #B
>     puts "back to root " + i.to_s
>     i += 1
> end

Continuations don't capture a frozen state but rather a live environment
- you can return to the same continuation and encounter different local
state each time.

i = 0
callcc{|cc| puts "assign once"; $cc = cc}
i += 1
puts(i)
$cc.call unless i == 3

So you don't need to 'update' your continuation references in order to
keep track of changed state (such as the num value inside loller). The
reason you require the assignment to 'that' is because on the initial
method invocation it will have the 'wrong' value - it will transfer back
to #A, and you have to fix that after the first control transfer back
into loller via 'well' to point to #B instead. (Which is also why you
get two successive messages from loller before the root messages kick
in.)

A slightly modified version of your code:

def loller(id, num, that)
  loop do
    puts id.to_s + " " + num.to_s
    num += 1
    sleep(0.5)
    callcc { |here| that.call(here) }
  end
end

i = 0
well = nil
while true
  if(well.nil?)
    well = callcc { |there| loller(1,34,there) }
  else
    callcc { |there| well.call(there) }
  end
  puts "back to root " + i.to_s
  i += 1
end

Best regards,
Patrick
Brian C. (Guest)
on 2009-02-03 13:37
Paul w Florczykowski wrote:
> Anybody who understand this, please explain. Big thanks in advance.

The way I think of it: firstly

* A closure is an environment in which variables are evaluated and
stored

Once you 'get' closures, then:

* A continuation is a closure plus an execution pointer

Some closure examples I read a while back were not helpful. One I think
talked about going across a railway crossing, getting run over by a
train, and then rewinding to before you went across.

Using a continuation, you can rewind to before you went across, but
you'll still be dead :-)

Regards,

Brian.
Paul w F. (Guest)
on 2009-02-03 20:04
Patrick R. wrote:
> ...
> So you don't need to 'update' your continuation references in order to
> keep track of changed state (such as the num value inside loller). The
> reason you require the assignment to 'that' is because on the initial
> method invocation it will have the 'wrong' value - it will transfer back
> to #A, and you have to fix that after the first control transfer back
> into loller via 'well' to point to #B instead. (Which is also why you
> get two successive messages from loller before the root messages kick
> in.)
> ...
> Best regards,
> Patrick

Appreciate the reply! it actually helped me understand this! Thanks
again!
This topic is locked and can not be replied to.