Refer to here for more details.
I wrote a CPS transformer for Common Lisp in a few days after thinking in lisp terms only three months for now. I think it means lisp is great, actually I would never try to do the same thing in Java. -- Levente Mészáros
The code is not tested too much and I'm sure it can be improved. It's just a toy right now, but an interesting one, I think...
Also consider cl-cont - a delimited continuations library for Common Lisp initially written for cl-weblocks.
How does this one compare to Marco Baringer's transformer (used in UCW), part of his arnesi/bese tools? -- Jörg Höhle
I did take a look at Marco's stuff and this one is quite similar to that, although I don't know if arnesi uses explicit environments or relies on captured variables like this one. Actually I could not figure it out probably because of my little lisp experience. -- Levente Mészáros
After consulting with Marco, this is somewhat different in that it does not maintain during runtime its own environment (e.g. variable bindings), but relies on the VM's and on the fact that closures capture it.
Discussing with David Lichteblau I think the closure (the continuation) that is returned can be saved and restored via SB-HEAPDUMP (in SBCL), so you may have persistent continuations. Well, you already have them in arnesi/cc in a somewhat different way. -- Levente Mészáros
I have added a persistent continuation test below.
Code
Test
Try this to test (I have used LispWorks). Note how the continuation (a closure) is returned and reused. The speed is interestingly only x20 slower compared to normal compiled code. It probably comes from heavy memory usage as you can see from the timing.CL-USER 7 > (@defun ii () (iter (for i from 0 to 3) (call/cc #'ret/cc) (collect i))) @II* CL-USER 8 > (ii) (0 1 2 3) CL-USER 9 > (@ii*) (0 1 2 3) CL-USER 10 > (@ii) #<closure 206834B2> CL-USER 11 > (@eval *) #<closure 2068A0DA> CL-USER 12 > (@eval *) #<closure 2068D50A> CL-USER 13 > (@eval *) #<closure 20690FFA> CL-USER 14 > (@eval *) (0 1 2 3) ... CL-USER 39 > (time (dotimes (x 100000) (ii))) Timing the evaluation of (DOTIMES (X 100000) (II)) user time = 1.031 system time = 0.000 Elapsed time = 0:00:01 Allocation = 2464 bytes standard / 17603267 bytes conses 0 Page faults NIL CL-USER 40 > (time (dotimes (x 100000) (@ii*))) Timing the evaluation of (DOTIMES (X 100000) (@II*)) user time = 18.328 system time = 0.000 Elapsed time = 0:00:18 Allocation = 821607408 bytes standard / 401503377 bytes conses 0 Page faults NIL CL-USER 41 > CL-USER 42 > (@ii*) (0 1 2 3)
Expansion
The above iter example expands into this:
Persistent continuation
Try SBCL and SB-HEAPDUMP and the CPS transformation above on the following example.
Persistent continuation test
The following is a test session using SBCL. Note where the system was restarted and how the continuation is used.
CL-USER> (@start #'@demo) 24576 bytes written #<CLOSURE (LAMBDA (I)) {B2E6A5D}> CL-USER> ; SBCL Port: 32822 Pid: 14363 ... CL-USER> (@continue) ; loading continuation.heap[0] mmap 0.0s fixup 0.001s done 24576 bytes written #<CLOSURE (LAMBDA (I)) {B394CA5}> CL-USER> ; SBCL Port: 32824 Pid: 14729 ... CL-USER> (@continue) ; loading continuation.heap[0] mmap 0.0s fixup 0.0s done 24576 bytes written #<CLOSURE (LAMBDA (I)) {B3BC4D5}> CL-USER> (@continue) ; loading continuation.heap[0] mmap 0.002s fixup 0.001s done 24576 bytes written #<CLOSURE (LAMBDA (I)) {B3E44FD}> CL-USER> (@continue) ; loading continuation.heap[0] mmap 0.0s fixup 0.0s done 4096 bytes written (0 1 2 3) CL-USER> (@run #'@demo) 49152 bytes written ; loading continuation.heap[0] mmap 0.001s fixup 0.0s done 49152 bytes written ; loading continuation.heap[0] mmap 0.0s fixup 0.001s done 49152 bytes written ; loading continuation.heap[0] mmap 0.001s fixup 0.0s done 49152 bytes written ; loading continuation.heap[0] mmap 0.003s fixup 0.001s done 4096 bytes written (0 1 2 3)
programming tips