yufit_in_Japan
yufit_in_Japan

Reputation: 583

How to use call/cc for non-local exit in Scheme

Currently, I am studying Scheme language. I'm confused in how to use call-with-current-continuation.(call/cc) For a better understanding it, I wrote an example code for non-local exits. But it doesn't work properly.

Does anyone know why? Any help would be appreciated. Thanks in advance

[example code]

(define (product ls)
  (call/cc
   (lambda (return)
     (cond
      ((null? ls ) =>
       (begin
         (display "list end")
         (newline)
         1)) ;; NG
         ;;(return 1)) ;; OK

      ((not (number? (car ls))) =>
       (begin
         (display "not number")
         (newline)
         (return 0)))
      (else =>
            (begin
              (display (car ls))
              (newline)
              (* (car ls) (product (cdr ls)))))))))

[repl output]

gosh> (product '(1 2 a 3)) ; it works as I expected.
==> 1
==> 2
==> not number
==> 0 (return)

gosh> (product '(1 2 3)) ;; it doesn't work as I expected. I expect 6 as return value.
==> 1
==> 2
==> 3
==> list end
*** ERROR: invalid application: (1 #t)

Upvotes: 0

Views: 230

Answers (1)

John Clements
John Clements

Reputation: 17223

There are a couple of things going on here.

First and foremost, it looks like the => you're inserting into your cond clauses is causing the problem. In Scheme, the => has a special meaning... which you don't want. Take them out, and I think you'll see that your code behaves as you expect.

BUT: your use of call/cc is not actually causing a non-local exit, as I believe you're intending. That is, my guess is that you want the zero to bypass all of the waiting multiplies, and it's not. To see this, change the 0 into something that can't be multiplied---say, the string "not a number"--and watch it fail.

This is because you're re-binding return on each call to the function. I think you probably actually want something like this:

(define (product ls)
  (call/cc
   (lambda (return)
     (letrec ([loop
              (lambda (ls)
                (cond
                  ((null? ls )
                   (begin
                     (display "list end")
                     (newline)
                     1)) ;; NG
                  ;;(return 1)) ;; OK

                  ((not (number? (car ls)))
                   (begin
                     (display "not number")
                     (newline)
                     (return "not a number")))
                  (else 
                   (begin
                     (display (car ls))
                     (newline)
                     (* (car ls) (loop (cdr ls)))))))])
       (loop ls)))))

(product '(1 2 a 3))

... which produces this output:

1
2
not number
"not a number"
>

Upvotes: 4

Related Questions