[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Paul Graham <paulgraham@yahoo.com>] Re: What is alightweight language

Title: Re: [Paul Graham <paulgraham@yahoo.com>] Re: What is a
At 12:14 PM -0500 12/13/01, jmarshall@mak.com wrote:
Matthias Felleisen <matthias@ccs.neu.edu> writes:

> Paul writes:
>   As in many uses of continuations, you don't actually need
>   call/cc-- you can fake continuations using carefully constructed
>   closures-- but having call/cc makes it cleaner and easier.
> It's not just cleaner and easier, it maintains invariants automatically. If
> your programmer abuses your patterns just a bit, all kind of things can
> happen and you don't even know.

I'm not sure I understand what you mean here.  I thought that Paul was
suggesting using CPS in lieu of call-with-current-continuation.  I
don't see CPS as being any `dirtier' that call-with-current-continuation.

It's "dirtier" because programming in a CPS discipline requires that the whole program (libraries, etc.) obey the CPS invariants.  So, suppose I want to write a short-cutting 'andmap' that accepts a function and a list (uh, in scheme):

; andmap : ('a -> boolean) (listof boolean) -> boolean

(define (andmap fn lst)
   (lambda (escape)
     (letrec ([loop
               (lambda (remaining)
                 (cond [(null? remaining) #t]
                       [(fn (car remaining)) (loop (cdr remaining))]
                       [else (escape #f)]))])
       (loop lst)))))

; test expression
  (andmap (lambda (x) (= x 9)) '(9 9 9))
  (not (andmap (lambda (x) (= x 9)) '(9 4 a))))
; CPS'ed version:
; andmap: ('a (boolean ->) -> ) (listof boolean) (boolean -> ) ->
(define (andmap-cps fn lst escape-k)
     (letrec ([loop
               (lambda (remaining k)
                 (if (null? remaining)
                     (k #t)
                     (fn (car remaining)
                         (lambda (fn-result)
                           (if fn-result
                               (loop (cdr remaining) k)
                               (escape-k #f))))))])
       (loop lst escape-k)))

; test expression
  (andmap-cps (lambda (x k) (k (= x 9))) '(9 9 9) (lambda (x) x))
  (not (andmap-cps (lambda (x k) (k (= x 9))) '(9 4 a) (lambda (x) x))))

In the second (CPS'ed) case:

1) reading it is horrible, and
2) writing it is horrible, even though
3) I didn't have the energy to push the CPS through the primitives, but most of all
4) as Matthias points out, if andmap is called with a procedure that does not obey the CPS invariants, the whole computation falls off the back of the dump truck.

... unless you were just talking about using a CPS-ing compiler to implement call/cc.

john clements