On Thu, Dec 20, 2001 at 07:08:03AM +0900, Steven Grady wrote:
> Based on a discussion on another list, I was thinking about
> continuations recently.  One of the interesting (i.e. brainmelt)
> examples of continuations in Scheme is: (callcc callcc).
> 
> I was trying to figure out how to express this in Ruby.  You can't
> say:
>     callcc {|cc| callcc(cc)}
> because the inner callcc isn't allowed to take a continuation as an
> argument -- it wants a block (it won't even take a Proc).
> 
> This leads me to my first question:
>   Can the equivalent of (callcc callc) be expressed in Ruby?  How
> about the super-brainmelt: ((callcc callcc) (callcc callcc))?

I think the following will work:

  def callcc2(obj)
    return callcc { |*args| obj.call(*args) }
  end
  callcc2(method(:callcc2))

But this raises a question in my mind: what possible contorted use do
you have for such a construct?

> The reason that it's so easy in scheme is that continuations basically
> are like lambda expressions taking one argument.  It would be nice if
> the things "like lambda expressions" in Ruby, i.e. blocks, Procs,
> Methods, and Continuations, all behaved the same way.  Instead, they
> are all different: continuations require a block; Procs and Methods
> have the #arity method, but Continuations don't, etc.
> 
> So my second question is: Is there any reason for this?  Would the
> language be cleaner if there were a closer relationship between these
> items (e.g. if they all inherited from Proc)?

There are some cases in the current implementation of Ruby where these
objects all work in the same way.  There are other cases where they
don't.  The cases where they don't, from what I can tell, are due to
some of the internals of Ruby.  A Proc is a BLOCK (as is a Binding, but
a Binding is not callable), a Method is a METHOD, and a Continuation is
a thread.  They are all callable objects (that is, they respond to the
call() method), but internally, they must all be called in a different
way.

There are some cases where this is justified.  For example,
set_trace_func takes a Proc and only a Proc, because it is called quite
a lot, and being able to call the Proc very quickly is a good thing.  On
the other hand, there's no reason why a Proc cannot be instantiated from
any callable object.

In the case you presented, though, just think of Ruby's callcc as a
version of MzScheme's let/cc.  Perhaps Ruby just has a poor naming
choice here.

Paul