schemeracketlambdaletevaluator

Using a list as argument names for lambda scheme/racket


I'm working on a scheme evaluator in scheme. I need to implement let, I have parsed so that I have variable names, values to input and the body of the function. I need to return a lambda function using the parsed information and as such I have the following code:

(define (eval-let exp env)
  ((lambda (let-variables (let-bindings exp)) (let-body exp)) (let-exp (let-bindings exp))))

(let-variables (let-bindings exp)) evaluates to a list of variable names (ex: '(x y)), so I'm basically evaluating to this:

((lambda '(x y) (* x y)) '(2 3))

The scheme interpreter simple says: #%plain-lambda: not an identifier in: (let-bindings exp) which I'm guessing is because it wants a set of identifiers, not a list of values.

How do I turn my list of values into a set of identifiers?


Solution

  • To implement a let expression in your own interpreter first you have to transform it into a lambda application, something similar to this (procedure names should be self-explanatory):

    (define (let->combination exp)
      (let* ((bindings (let-bindings exp))
             (body     (let-body exp))
             (exps     (bindings-all-exps bindings))
             (lambda   (make-lambda (bindings-all-vars bindings) body)))
        (make-application lambda exps)))
    
    (define (make-lambda parameters body)
      (list* 'lambda parameters body))
    
    (define (make-application proc . args)
      (cond ((null? args) (list proc))
            ((list? (car args)) (cons proc (car args)))
            (else (cons proc args))))
    

    And after the syntax transformation has been performed you can proceed to evaluate it:

    (eval (let->combination exp) env)
    

    What I'm trying to point out is that you shouldn't try to evaluate it directly. Also be careful, the code you're generating has a couple of incorrect quotes:

    ((lambda '(x y) (* x y)) '(2 3))
             ^               ^
           here            here
    

    It should look like this instead:

    ((lambda (x y) (* x y)) 2 3)