3

As an exercise to learn call/cc and macros, I tried to define goto.

(define-syntax label
  (syntax-rules ()
           ((_ name)
        (begin
          (define name)
          (call/cc (lambda (c) (set! name c)))))))

(define (goto label) (label))

(define i 0)
(label start)
(display i) (newline)
(set! i (+ i 1))
(if (< i 3) (goto start))
(display "done") (newline)

It works in guile-2.0, but in chez scheme and racket (r6rs) it just prints

0
done

Which implementation is correct?

1 Answers1

5

I think top level is different in different implementations. For Racket, call/cc captures continuation up to a single, top-most expression, not the whole program. I think Guile captures up to the whole program. Hence the difference.

You can get Guile's behavior by writing your code in a function:

#lang r5rs

(define-syntax label
  (syntax-rules ()
    ((_ name)
     (begin
       (define name #f)
       (call-with-current-continuation (lambda (c) (set! name c)))))))

(define (goto label) (label))

(define (main)
  (define i 0)
  (label start)
  (display i) (newline)
  (set! i (+ i 1))
  (if (< i 3) (goto start) #f)
  (display "done") (newline))

(main)

This outputs:

0
1
2
done

Note that if you use Racket, you can create a new language and redefine toplevel (via #%module-begin) to get Guile's behavior without any modification to the program.

Sorawee Porncharoenwase
  • 6,305
  • 1
  • 14
  • 28