Continuations II

1 view
Skip to first unread message

Leslie P. Polzer

unread,
Apr 21, 2008, 3:58:27 PM4/21/08
to weblocks
I'd like to use CL-CONT to escape from a MAPCAR. I'm not sure whether
this is possible (although I can't see why it should not), but in any
case I want to know what happens here:

(with-call/cc
(let/cc k
(let ((i 0))
(mapcar (lambda (x)
(when (> i 1)
(funcall k t))
(format t "~D ~S~%" (incf i) x))
'(a b c d)))))

Output:

1 A
2 B
3 C
4 D
(NIL NIL NIL NIL)

In my understanding of escaping continuations control flow is passed
at FUNCALL, which calls the function that models the rest of the
(delimited) computation. I suppose (and here I'm already treading on
thin ice) the FUNCALL returns normally (with what result? That of the
rest of the delimited computation?) and the lambda/mapcar resumes its
normal course of operation.

Is there a way to make the call of the continuation behave like a true
escape, discarding all that follows its call?

Leslie

Sohail Somani

unread,
Apr 21, 2008, 4:12:37 PM4/21/08
to webl...@googlegroups.com
Leslie P. Polzer wrote:
> I'd like to use CL-CONT to escape from a MAPCAR. I'm not sure whether
> this is possible (although I can't see why it should not), but in any
> case I want to know what happens here:

Maybe return-from is what you need?

Vyacheslav Akhmechet

unread,
Apr 22, 2008, 12:00:06 AM4/22/08
to webl...@googlegroups.com
On 4/21/08, Leslie P. Polzer <leslie...@gmx.net> wrote:
> I'd like to use CL-CONT to escape from a MAPCAR.
This won't work. Remember, the body of MAPCAR isn't transformed, so
the whole thing will give an undefined result. You could either write
your own version of mapcar that you transform, or use the loop macro
for the time being.

Future versions of cl-cont should provide transformable versions of
commonly used built-in functions, but this hasn't been a high
priority.

> (with-call/cc
> (let/cc k
> (let ((i 0))
> (mapcar (lambda (x)
> (when (> i 1)
> (funcall k t))
> (format t "~D ~S~%" (incf i) x))
> '(a b c d)))))
>
> Output:
>
> 1 A
> 2 B
> 3 C
> 4 D
> (NIL NIL NIL NIL)

(FUNCALL k t) calls the rest of the computation (which is essentially
empty), returns, FORMAT returns nil, and MAPCAR continues to execute.
You should really treat this as undefined behavior because MAPCAR
isn't transformed here. If you use LOOP, or write your own version of
MAPCAR, it will work as you expect.

> In my understanding of escaping continuations control flow is passed
> at FUNCALL, which calls the function that models the rest of the
> (delimited) computation.

That's correct.

> I suppose (and here I'm already treading on
> thin ice) the FUNCALL returns normally

Yes, this is correct.

> (with what result? That of the
> rest of the delimited computation?)

Funcall invokes the rest of the computation, and simply returns
whatever value it computes.

> the lambda/mapcar resumes its normal course of operation.

Well, if this were to work correctly, only the first element of the
list would be processed. Funcall would then transfer control to to the
rest of the continuation (which in this case is empty), and true would
be returned. Actually, in cl-cont, the return value of format would be
returned, not true, because calling the rest of the computation via
funcall doesn't make everything after funcall unreachable. But again,
this doesn't work as expected because MAPCAR isn't transformed.

> Is there a way to make the call of the continuation behave like a true
> escape, discarding all that follows its call?

You mean ignore the code after funcall/or funcall automatically? One
would to do that would be to set up catch blocks and have cl-cont
automatically throw to them, but this generally isn't a good idea.
There was a post on this somewhere by Bill Clementson regarding Arnesi
library. Basically, delimited continuations don't capture the whole
computation, so if you transfer control like you do in a real
continuation you'll have no way to implement interesting things (like
threads/processes, coroutines, etc) since unlike in scheme, once you
invoke the delimited continuation the old computation doesn't get
thrown away.

Hope this helps. It can be quite tricky to understand, and is
unfortunately tricky to explain. Also, I need to refresh my memory
every time I look at this, somehow this refuses to just settle down
properly in my mind :)

Leslie P. Polzer

unread,
Apr 22, 2008, 2:22:45 AM4/22/08
to weblocks
On Apr 21, 10:12 pm, Sohail Somani <soh...@taggedtype.net> wrote:

> Maybe return-from is what you need?

Yeah, intuitively. Unfortunately RETURN-FROM doesn't work with non-
local tagbodies.
Try it :)

Leslie P. Polzer

unread,
Apr 22, 2008, 2:25:12 AM4/22/08
to weblocks
> You mean ignore the code after funcall/or funcall automatically? One
> would to do that would be to set up catch blocks and have cl-cont
> automatically throw to them, but this generally isn't a good idea.

I have solved this indeed using plain CATCH/THROW. It's not pretty,
but it can be wrapped in a macro. CL-CONT isn't needed then.

Leslie P. Polzer

unread,
Apr 22, 2008, 4:55:35 AM4/22/08
to weblocks
RETURN-FROM works indeed. I have mixed it up with TAGBODY and GO when
it didn't work for me.
Thanks!
Reply all
Reply to author
Forward
0 new messages