Search code examples
schemesemanticslanguage-designchez-scheme

Why can you redefine `lambda`?


I do not understand the following behavior between these two Scheme programs:

Program 1:

(define a
  (begin
    (display "hmmm")
    (newline)
    lambda))

This program, run using scheme test.ss, gives me a syntax error at the lambda line without printing out the string "hmm".

Program 2:

(define lambda 5)
(define a (+ 1 2 lambda))

The end result here is that a is equal to 8.


The behavior in the first program is the behavior I expect in both programs. What confuses me is why the second program does not fail with a syntax error. Clearly I am redefining lambda, but I would think that this would fail with a syntax error before that code could actually be run. It seems to me that to know that this is not a syntax error you would need to actually run the program, but if this was the behavior then I would expect the first program to display the string before it errors out.

In short, why does the first program result in a syntax error while the second program does not?


Solution

  • In Scheme lambda and define are top level bindings in the compiler phase. define takes exactly two operands and since you supplied 4 it should react to that first. So lets mend that first:

    (define a 
      (begin 
        (display "hmmm")
        (newline)
        lambda)))
    

    Now you get an error about lambda. It's the primitive form to create procedures so the compiler thinks you are using it wrong:

    (lambda (x) (+ x x)) ; implementation of double
    

    If you had defined lambda as a variable then the error won't happen since even though this is the way to make procedures, you can make variables with the same name.

    (define lambda 10)
    (define a 
      (begin (display "hmmm")
      (newline)
      lambda))
    ; ==> 10 (and it printed "hmmm")
    

    The compiler knows the lexical nature of the code. It knows exactly which bindings are defined and which are to level and in which phase. Top level lambda is no longer available.

    Now in your second program you define lambda and then use it, just like im my last example that also works.

    Note that in R5RS the compiler assumes redefinitions og library and primitive procedures are compatible and might constant fold:

    (define (+ a b)
      (string-append a b))
    (display (+ 4 5)) ; displays 9
    

    In it's defence I have violated the R5RS report by making my + incompatible. If it weren't top level it would have been ok:

    (let ((+ (lambda (a b) (string-append a b))))
      (+ 4 5)) ; no loinger top level, will signal n error!