šŸ““ literature/lisp-in-small-pieces.md by @ryan ā˜†

Lisp in Small Pieces

tags : [[Lisp]] [[programming languages]]

The code examples in these notes will use [[Racket]], since Racket is a mature [[Scheme]] implementation.

1. The Basics of Interpretation

Starts on p. 19

2. Lisp, 1, 2, … ω

Source code reference

f.evaluate

(define (f.evaluate e env fenv)
  (if (atom? e)
      (cond ((symbol? e) (lookup e env))
            ((or (number? e) (string? e) (char? e)
                 (boolean? e) (vector? e) )
             e )
            (else (wrong "Cannot evaluate" e)) )
      (case (car e)
        ((quote)  (cadr e))
        ((if)     (if (f.evaluate (cadr e) env fenv)
                      (f.evaluate (caddr e) env fenv)
                      (f.evaluate (cadddr e) env fenv) ))
        ((begin)  (f.eprogn (cdr e) env fenv))
        ((set!)   (update! (cadr e)
                           env
                           (f.evaluate (caddr e) env fenv) ))
        ((lambda) (f.make-function (cadr e) (cddr e) env fenv))
        (else     (evaluate-application (car e)
                                        (f.evlis (cdr e) env fenv)
                                        env
                                        fenv )) ) ) )

(define (f.evlis exps env fenv)
  (if (pair? exps)
      (cons (f.evaluate (car exps) env fenv)
            (f.evlis (cdr exps) env fenv) )
      '() ) )

(define (f.eprogn exps env fenv)
  (if (pair? exps)
      (if (pair? (cdr exps))
          (begin (f.evaluate (car exps) env fenv)
                 (f.eprogn (cdr exps) env fenv) )
          (f.evaluate (car exps) env fenv) )
      empty-begin ) )

(define (f.make-function variables body env fenv)
  (lambda (values)
    (f.eprogn body (extend env variables values) fenv) ) )

(define (lookup id env)
  (if (pair? env)
      (if (eq? (caar env) id)
          (cdar env)
          (lookup id (cdr env)) )
      (wrong "No such binding" id) ) )

(define (update! id env value)
  (if (pair? env)
      (if (eq? (caar env) id)
          (begin (set-cdr! (car env) value)
                 value )
          (update! id (cdr env) value) )
      (wrong "No such binding" id) ) )

(define (extend env variables values)
  (cond ((pair? variables)
         (if (pair? values)
             (cons (cons (car variables) (car values))
                   (extend env (cdr variables) (cdr values)) )
             (wrong "Too less values") ) )
        ((null? variables)
             (if (null? values)
                 env
                 (wrong "Too much values") ) )
        ((symbol? variables) (cons (cons variables values) env)) ) )

(define (invoke fn args)
  (if (procedure? fn)
      (fn args)
      (wrong "Not a function" fn) ) )

(define (evaluate-application fn args env fenv)
  (cond ((symbol? fn)
         (invoke (lookup fn fenv) args) )
        ((and (pair? fn) (eq? (car fn) 'lambda))
         (f.eprogn (cddr fn)
                   (extend env (cadr fn) args)
                   fenv ) )
        (else (wrong "Incorrect functional term" fn)) ) )

3. Escape & Return: Continuations

4. Assignment and Side Effects

5. Denotational Semantics

[[Ī»-calculus]] crash course

Variable

Akin to a function argument \(\forall x \in Variable, x \in \Lambda\)

Abstraction

Akin to a function body \(\forall x \in Variable, \forall M \in \Lambda, \lambda x . M \in \Lambda\)

Combination

\(\forall M,N \in \Lambda, (M N) \in \Lambda\)

β-reduction

When we apply a function with a body \(M\) and a variable \(x\) to a term \(N\), we get a new term which is the body of \(M\) of the function with the variable \(x\) replaced by the term \(N\), so:

\(M[x \longrightarrow N]\)

Further

\((\lambda x.M N) \xrightarrow{\beta} M[x \rightarrow N]\)

A redex is a reducible expression.

Chapter notes

6. Fast Interpretation

In order to speed up interpretation, an [[activation record]] will be used to provide a function with its arguments.

The function signature for the interpreter is essentially:

\begin{document} meaning: \text{Program} x \text{Environment} \rightarrow \text{(Activation-Record x Continuation)} \rightarrow \text{Value} \end{document}

Where Program x Environment is static and Acivation-Record x Continuation is dynamic.

For convenience, I’ve reproduced the notation conventions used in the book here:

Notation Meaning
e Expression, form
r Environment
sr, … , v* Activation record
v Value (integer, pair, closure, etc.)
k Continuation
f Function
n Identifier

The fast interpreter begins with defining various meaning functions, which resolve input to a value.

meaning-quotation is defined as such:

(define (meaning-quotation v r)
  (lambda (sr k)
    (k v)))

The fast interpreter stores global variables and local variables separately.

The fast interpreter is generally faster because it pre-treats the values in a compiler-like manner, avoiding unnecessary memory allocations.

Closures are handled as such:

(struct closure (code closed-environment))

(define (invoke f v*)
  (if (closure? f)
      ((closure-code f) v* (closure-closed-environment f))
      (wrong "Not a function" f)))

Although this chapter complicates the interpreters written thus far considerably, it does also speed up interpretation.