Monday, March 15, 2010

block/return in scheme

Continuations in Scheme - they're not necessarily all that hard. You can use them to prematurely return from a function, as in the following example:

(call-with-current-continuation
(lambda (return)
(begin
(display "One ")
(return #t)
(display "Two ")
#f)))


In the above example, it would print "One ", and bail out by returning the value #t. The remainder of the lambda is never executed. Note that 'return' is a paramater, so you could choose whatever name you wanted to.

It is useful to have some syntactic sugar for the above. A standard name is 'let-cc', defined as follows:

(define-syntax let-cc
(syntax-rules ()
((let-cc variable . body)
(call-with-current-continuation
(lambda (variable) . body)))))


I can then type things more conveniently:

(let-cc return
(display "One ")
(return #t)
(display "Two ")
#f)


Note that my choice of use of the word 'return' is still arbitrary. It's very flexible, because I can have any number of 'named' blocked, and return to whatever part of the program I am interested in.

Suppose I want to give up some flexibility, and that I want 'return' to be part of my syntax. I want a block/return (similar to Lisp's block nil) construction. 'return' means that I want to return from the block. To put it in more concrete terms, I want to be able to write:

(block
(write-line "this is printed")
(return "this is returned")
(write-line "this is never printed"))


A macro which satisfies this is:

(define-syntax block
(lambda (x r c)
(let ((body (cdr x)))
`(call-with-current-continuation
(lambda (return) ,@body)))))


The above was written for Chicken Scheme. Other Schemes might not support it - it's certainly do-able in other schemes - but the implementation might be rather hairier (check out the cls link below, for example).

Further reading:

No comments: