4
votes

I am reading the r5rs scheme standard and find that the begin() is actually a library syntax, which means that it could be defined by scheme itself, and the standard gives an implementation at the end of the standard.

I followed the r5rs to implemented begin() using define-syntax like below:

(define-syntax mybegin
  (syntax-rules ()
                ((mybegin expr) expr)
                ((mybegin expr1 expr2 ...)
                 (let ((x expr1))
                   (mybegin expr2 ...)))))

and then I tried to implement it using function, here is my code:

(define begin-func
  (lambda (expr1 expr2)
    ((lambda (x) expr2) expr1)))

here are my test cases:

(define x 3)
(define y 3)
(mybegin
  (set! x 4)
  (set! x 5))
(begin-func
  (set! y 4)
  (set! y 5))

I ran my code in MIT-SCHEME and Racket using #lang scheme, x is 5 in both MIT-SCHEME and Racket, however, y is 4 in MIT-SCHEME but 5 in Racket

So, Here is my question:

  1. Is it true that we could really implement begin() using pure functional scheme?
  2. Is there anything wrong in my code, both the code using macro and the code using function?
  3. why does same code behaves differently in MIT-SCHEME and Racket?
1

1 Answers

3
votes

begin is a special form evaluates each element in order and that evaluates to the very last expression. You will never need begin in a purely functional Scheme, but it's possible to get similar functionality as begin in a functional manner in a Scheme that doesn't have begin as a special form or embedded in lambda forms or relatives. It's only one exception and that's define inside it. define in a top level begin would be defined globally while a imitation would use procedures to get the evaluation in order and define would then only become a local bind that dies when the procedure goes out of scope.

begin has to be defined as syntax because if you make a procedure like:

(define (mybegin . args)
  ...)

All arguments when mybegin is called will be evaluated in an implementation specific order. The report says the evaluation needs to be consequent so that you won't see one implementation getting 4 one time and 5 another, but you'll see one of them happening every time for that same procedure. It's not guaranteed that evaluation will happen in the same order on two different procedures too, but many Scheme implementations usually does it in the same order.

Racket always evaluate arguments in order, which is OK because the report says you can do it however you'd like, while MIT at least sometimes evaluate in the opposite order.