introduction to lisp for scheme users. what makes lisp different? built-in support for lists...

47
Introduction to Lisp For Scheme Users

Upload: jocelyn-powell

Post on 12-Jan-2016

224 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Introduction to Lisp

For Scheme Users

Page 2: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

What Makes Lisp Different?

• Built-in Support for Lists• Automatic Storage Management• Dynamic Typing• First-Class Functions• Uniform Syntax• Interactive Environment• Extensibility• History

Page 3: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Lisp vs. Scheme

1. Lisp has much more built-in functions and special forms, the Scheme language definition takes 45 pages while Common Lisp takes 1029 pages)

2. Apart from lexical variables Lisp also has special variables

3. Scheme uses one name space for functions, variables, etc., Lisp doesn’t.

4. Scheme evaluates the function part of a function call in exactly the same way as arguments, Lisp doesn’t.

5. Lisp functions can have rest, optional and keyword parameters. Scheme functions only can have the equivalent of a rest parameter.

Page 4: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Lisp vs. Scheme (2)

6. Lisp has block, return, go or throw, in Scheme a single function (call-with-current-continuation or call/cc) replaces all these and does much more.

7. Lisp has built-in packages while package-like structures can be implemented in Scheme using lexical variables.

8. Lisp has standard macros, Scheme doesn’t although most implementations provide macros as an extension. Still true in latest definition of Scheme?

9. Lisp has special forms (loop, do, dotimes, …) for looping, in Scheme the user is asked to use tail-recursion that is implemented efficiently.

Page 5: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Scheme vs. Lisp

• var• constant• (quote x) or ’x• (set! var x)• (if p a b)• (lambda parms x…)• (fn arg …)

• #t, #f, ()• (define var exp)• (define (fn parm…) body)

• var• constant• (quote x) or ’x• (setq var x)• (if p a b)• #’(lambda parms x…)• (fn arg …) or (funcall fn

arg …)• t, nil, nil• (defparameter var exp)• (defun fn (parm…) body)

Page 6: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Scheme vs. Lisp (2)

• char-ready?• char?• eq?• equal?• eqv?• even?• for-each• integer?• map• negative?• pair?• procedure?

• listen• characterp• eq• equal• eql• evenp• mapc• integerp• mapcar• minusp• consp• functionp

Page 7: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Scheme vs. Lisp (3)

• set!• set-car!• vector-set!• string-set!

• setq, setf• replaca, setf• setf• setf

Page 8: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Parameters in Scheme

(define (foo-1 arg1 . rest)

body)

(define (bar arg1 arg2)

body)

(foo-1 1 2 3 4 5)

arg1 1

rest (2 3 4 5)

(foo-1 1)

arg1 1

rest ()

(bar 1 2)

Page 9: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Parameters in Lisp

(defun foo-1 (arg1 &rest rest)

body)

(defun foo-2 (arg1 &optional (arg2 default-value))

body)

(foo-1 1 2 3 4 5)arg1 1rest (2 3 4 5)

(foo-1 1 2 3 4 5)arg1 1rest (2 3 4 5)

(foo-2 2)arg1 2arg2 default-value

(foo-2 2 3)arg1 2arg2 3

Page 10: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Parameters in Lisp

(defun foo-3 (&key (op ‘+)(range 100) (n 10)) body … )

(foo-3 :n 5)op +range 100

n 5(foo-3 :n 20 :op ’* :range 10)

op *range 10

n 20(foo-3) op +

range 100 n 10

Page 11: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Example: Names

;;; -*- Mode: Lisp; Syntax: Common-Lisp; -*-;;; Code from Paradigms of Artificial Intelligence Programming;;; Copyright (c) 1991 Peter Norvig

;;;; File intro.lisp: Miscellaneous functions from the introduction.

(defun last-name (name) "Select the last name from a name represented as a list." (first (last name)))

(defun first-name (name) "Select the first name from a name represented as a list." (first name))

(setf *names* '((John Q Public) (Malcolm X) (Admiral Grace Murray Hooper) (Spot) (Aristotle) (A A Milne) (Z Z Top) (Sir Larry Olivier)))

Page 12: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Names (2)

(defparameter *titles* '(Mr Mrs Miss Ms Sir Madam Dr Admiral Major General) "A list of titles that can appear at the start of a name.")

(defun first-name (name) "Select the first name from a name represented as a list." (if (member (first name) *titles*) (first-name (rest name)) (first name)))

Page 13: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Scheme Interpreter

scheme

interp

def-scheme-macro

*scheme-procs*

Top-level Functions

A Scheme read-eval-print loop

Evaluate an expression in an

environment

Define a Scheme macro

Special Variables

Some procedures to store in the

global environment

Page 14: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Scheme Interpreter (2)

set-var!get-var

set-global-var!get-global-var

extend-env

init-scheme-interpinit-scheme-proc

Auxiliary FunctionsSet a variable to a valueGet the value of variable in an environmentSet a global variable to a valueGet the value of a variable from the global environmentAdd some variables and values to an environmentInitialize some global variablesDefine a primitive Scheme procedure

Page 15: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Scheme Interpreter (3)

scheme-macro

scheme-macro-expand

maybe-add

print-proc

proc

Auxiliary Functions (cont.)

Retrieve the Scheme macro for a

symbol

Macro-expand a Scheme expression

Add an element to the front of a

non-singleton list

Print a procedure

Data Type (tail-recursive version only)

A Scheme procedure

Page 16: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Scheme Interpreter (4)

interp-begin

interp-call

map-interp

call/cc

last1

length=1

Functions (continuation version only)

Interpret a begin expression

Interpret a function application

Map interp over a list

call with current continuation

Previously Defined Functions

Select the last element of a list

Is this list of length 1?

Page 17: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Basic Scheme Interpreter1. If the expression is a symbol, look up its value in the environment2. If it is an atom that is not a symbol (such as a number), just return

it. 3. Otherwise, the expression must be a list. If the list starts with

quote, return the quoted expression4. If it starts with begin, interpret each subexpression, and return the

last one5. If it starts with set!, interpret the value and then set the variable to

that value6. If it starts with if, then interpret the test, and depending on

whether it is true or not, interpret the then-part or the else-part7. If it starts with lambda, build a new procedure – a closure over the

current environment8. Otherwise, it must be a procedure application. Interpret the

procedure and all it arguments, and apply the procedure value to the argument values

Page 18: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun interp (exp &optional env) "Interpret (evaluate) the expression exp in the environment env." (cond ((symbolp exp) (get-var exp env)) ((atom exp) exp) ((case (first exp) (QUOTE (second exp)) (BEGIN (last1 (mapcar #'(lambda (y) (interp y env)) (rest exp)))) (SET! (set-var! (second exp) (interp (third exp) env) env)) (IF (if (interp (second exp) env) (interp (third exp) env) (interp (fourth exp) env))) (LAMBDA (let ((parms (second exp)) (code (maybe-add 'begin (rest2 exp)))) #'(lambda (&rest args) (interp code (extend-env parms args env))))) (t ;; a procedure application (apply (interp (first exp) env) (mapcar #'(lambda (v) (interp v env)) (rest exp))))))))

Page 19: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun set-var! (var val env) "Set a variable to a value, in the given or global environment." (if (assoc var env) (setf (second (assoc var env)) val) (set-global-var! var val)) val)(defun get-var (var env) "Get the value of a variable, from the given or global environment." (if (assoc var env) (second (assoc var env)) (get-global-var var)))

(defun set-global-var! (var val) (setf (get var 'global-val) val))(defun get-global-var (var) (let* ((default "unbound") (val (get var 'global-val default))) (if (eq val default) (error "Unbound scheme variable: ~a" var) val)))

Page 20: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun extend-env (vars vals env) "Add some variables and values to an environment." (nconc (mapcar #'list vars vals) env))

Page 21: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defparameter *scheme-procs* '(+ - * / = < > <= >= cons car cdr not append list read member (null? null) (eq? eq) (equal? equal) (eqv? eql) (write prin1) (display princ) (newline terpri)))

(defun init-scheme-interp () "Initialize the scheme interpreter with some global variables." ;; Define Scheme procedures as CL functions: (mapc #'init-scheme-proc *scheme-procs*) ;; Define the boolean `constants'. Unfortunately, this won't ;; stop someone from saying: (set! t nil) (set-global-var! t t) (set-global-var! nil nil))

(defun init-scheme-proc (f) "Define a Scheme procedure as a corresponding CL function." (if (listp f) (set-global-var! (first f) (symbol-function (second f))) (set-global-var! f (symbol-function f))))

Page 22: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Syntactic Extension of the Basic Interpreter with Macros

• Once we have a basic Scheme interpreter, the remaining syntax can be defined as “derived expressions” in terms of the five primitives: quote, begin, set! , if and lambda

• The following forms are used (nearly) identically in Scheme and Lisp: let, let*, and, or, do, cond and case

Page 23: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Syntactic Extension of the Basic Interpreter with Macros (2)

The final three syntactic extensions are

unique to Scheme:

(define var val) or (define (proc-name arg …) body …)

(delay expression)

(letrec ((var init) …) body …)

Page 24: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Syntactic Extension of the Basic Interpreter with Macros (3)

• Macro: a form that the evaluator first expands into some other form which is then evaluated.

• Macros allow the user to extend the language, i.e. we have a programmable programming language

• First, we have to change interp to allow macros• Then, we have to provide a mechanism for

defining macros

Page 25: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Macro Evaluation

• Expansion, e.g. (schema-macro-expand

‘(let ((x 1)

(y 2))

(+ x y)))

((lambda (x y) (+ x y)) 1 2)

• Evaluation

Page 26: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun interp (x &optional env) "Interpret (evaluate) the expression x in the environment env. This version handles macros." (cond ((symbolp x) (get-var x env)) ((atom x) x) ((scheme-macro (first x)) (interp (scheme-macro-expand x) env)) ((case (first x) (QUOTE (second x)) … (t (apply (interp (first x) env) (mapcar #'(lambda (v) (interp v env)) (rest x))))))))

Page 27: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun scheme-macro (symbol) (and (symbolp symbol) (get symbol 'scheme-macro)))

(defmacro def-scheme-macro (name parmlist &body body) "Define a Scheme macro." `(setf (get ',name 'scheme-macro) #'(lambda ,parmlist .,body)))

(defun scheme-macro-expand (x) "Macro-expand this Scheme expression." (if (and (listp x) (scheme-macro (first x))) (scheme-macro-expand (apply (scheme-macro (first x)) (rest x))) x))

Page 28: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(def-scheme-macro let (bindings &rest body) `((lambda ,(mapcar #'first bindings) . ,body) .,(mapcar #'second bindings)))

(def-scheme-macro let* (bindings &rest body) (if (null bindings) `(begin .,body) `(let (,(first bindings)) (let* ,(rest bindings) . ,body))))

(def-scheme-macro and (&rest args) (cond ((null args) 'T) ((length=1 args) (first args)) (t `(if ,(first args) (and . ,(rest args))))))(def-scheme-macro or (&rest args) (cond ((null args) 'nil) ((length=1 args) (first args)) (t (let ((var (gensym))) `(let ((,var ,(first args))) (if ,var ,var (or . ,(rest args))))))))

Page 29: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(def-scheme-macro cond (&rest clauses) (cond ((null clauses) nil) ((length=1 (first clauses)) `(or ,(first clauses) (cond .,(rest clauses)))) ((starts-with (first clauses) 'else) `(begin .,(rest (first clauses)))) (t `(if ,(first (first clauses)) (begin .,(rest (first clauses))) (cond .,(rest clauses))))))

(def-scheme-macro case (key &rest clauses) (let ((key-val (gensym "KEY"))) `(let ((,key-val ,key)) (cond ,@(mapcar #'(lambda (clause) (if (starts-with clause 'else) clause `((member ,key-val ',(first clause)) .,(rest clause)))) clauses)))))

Page 30: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(def-scheme-macro define (name &rest body) (if (atom name) `(begin (set! ,name . ,body) ',name) `(define ,(first name) (lambda ,(rest name) . ,body))))

(def-scheme-macro delay (computation) `(lambda () ,computation))

(def-scheme-macro let-rec (bindings &rest body) `(let ,(mapcar #'(lambda (v) (list (first v) nil)) bindings) ,@(mapcar #'(lambda (v) `(set! .,v)) bindings) .,body))

Page 31: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Tail-Recursive Interpreter

• Lisp has many special forms for looping: do, do*, dolist, loop, …

(defun element-p (element list)(loop for el in list

when (eq el element) return t))• Scheme encourages to use tail-recursion

instead (define (element? element list)

(cond ((null? list) #f) ((eq? element (first list)) #t) (else (element? element (rest list))))

Page 32: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun interp (x &optional env) "This version is properly tail-recursive." (prog () :INTERP (return (cond ((symbolp x) (get-var x env)) ((atom x) x) ((scheme-macro (first x)) (setf x (scheme-macro-expand x))(GO :INTERP)) ((case (first x) (QUOTE (second x)) (BEGIN (pop x) ; pop off the BEGIN to get at the args ;; Now interpret all but the last expression (loop while (rest x) do (interp (pop x) env)) ;; Finally, rename the last expression as x (setf x (first x)) (GO :INTERP)) (SET! (set-var! (second x) (interp (third x) env) env)) (IF (setf x (if (interp (second x) env) (third x) (fourth x))) ; That is, rename the right expression as x (GO :INTERP)) ;; Continued on the next page

Page 33: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

((case (first x) ;; Continuation of the previous page (LAMBDA (make-proc :env env :parms (second x) :code (maybe-add 'begin (rest2 x)))) ;; A procedure application (t (let ((proc (interp (first x) env)) (args (mapcar #'(lambda (v) (interp v env))(rest x)))) (if (proc-p proc) ;; Execute procedure with rename+goto (progn (setf x (proc-code proc)) (setf env (extend-env (proc-parms proc) args (proc-env proc))) (GO :INTERP)) ;; else apply primitive procedure (apply proc args))))))))))

Page 34: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defstruct (proc (:print-function print-proc)) "Represent a Scheme procedure" code (env nil) (name nil) (parms nil))

(setf *proc* (make-PROC :name ’my-proc :parms ’ (x y) :code ’ (+ x y))

(defun print-proc (proc &optional (stream *standard-output*) depth) (declare (ignore depth)) (format stream "{~a}" (or (proc-name proc) '??)))

Page 35: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

An Interpreter Supporting Call/cc

• Lisp has different non-local exits, e.g. catch and throw (defun print-table (l) (catch ’not-a-number (mapcar #’print-sqrt-abs l))) (defun print-sqrt-abs (x) (print (sqrt (abs (must-be-number x))))) (defun must-be-number (x) (if (numberp x) x (throw ’not-a-number “huh?”)))

(print-table ’(1 4 -9 x 10 20)) 1, 2, 3, “huh?”

Page 36: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

An Interpreter Supporting Call/cc

• Scheme on the contrary has only one construct, call/cc:

(define (print-table l) (call/cc (lambda (escape) (set! not-a-number escape) (map print-sqrt-abs l))) (define (print-sqrt-abs x) (write (sqrt (abs (must-be-number x))))) (define (must-be-number x) (if (numberp x) x (not-a-number “huh?”)))

(print-table ’(1 4 -9 x 10 20)) 1, 2, 3, “huh?”

Page 37: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Continuations in Scheme

Consider the Scheme expression (* (f1 exp1) (f2 (f3 4) (f5 exp2)))

The continuation of (f3 4) in that expression is the function

(lambda (VoE)(* (f1 exp1) (f2 VoE (f5

exp2))))

The continuation c of an expression e is a function that awaits the value of e and proceeds the computation.

Page 38: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Continuations in Scheme (2)

Again, consider the Scheme expression

(* (f1 exp1) (f2 (f3 4) (f5 exp2)))

The continuation of (f2 (f3 4) (f5 exp2)) in that

expression is the function

(lambda (val)

(* (f1 exp1) val))

Page 39: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Continuations in Scheme (3)

In Scheme, every expression has a continuationand the evaluator always has a function athand representing that continuation. Furthermore, Scheme has a primitive function to get access to this continuation, i.e. call-with-current-continuation or call/cc.call/cc requires a function of one argument, andit immediately call this function thereby passing it the continuation of the entire call/cc expression.

Page 40: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Continuation Example

(define aFuture '())

(display (+ 2 (call/cc (lambda (cont)

(set! aFuture cont) 8))))

Page 41: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

Another Continuation Example:Error handling

(define error '())

(call/cc (lambda (cont) (set! error cont) (p)))

Page 42: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Last Continuation Example:Chronological Backtracking

(define (integer) (amb 1 (+ 1 (integer))))

(define (prime)

(let ((n (integer)))

(if (prime? n) n (fail))

(def-scheme-macro amb (x y)

‘(random-choice (lambda () ,x) (lambda () ,y)))

Page 43: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

A Last Continuation Example:Chronological Backtracking (2)

(define backtrack-points '())(define (fail) (let ((last-choice (first backtrack-points))) (set! backtrack-points (rest backtrack-points)) (last-choice)))(define (random-choice f g) (if (=1 (random 2))(choose-first f g) (choose-first g f)))(define (choose-first f g) (call/cc (lambda (k)

(set! backtrack-points (cons (lambda () (k (g))) backtrack-points))

(f))))

Page 44: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun interp (x env cc) "Evaluate the expression x in the environment env, and pass the result to the continuation cc." (cond ((symbolp x) (funcall cc (get-var x env))) ((atom x) (funcall cc x)) ((scheme-macro (first x))(interp (scheme-macro-expand x) env cc)) ((case (first x) (QUOTE (funcall cc (second x))) (BEGIN (interp-begin (rest x) env cc)) (SET! (interp (third x) env #'(lambda (val) (funcall cc (set-var! (second x) val env))))) (IF (interp (second x) env #'(lambda (pred) (interp (if pred (third x) (fourth x)) env cc)))) (LAMBDA (let ((parms (second x)) (code (maybe-add 'begin (rest2 x)))) (funcall cc #'(lambda (cont &rest args) (interp code (extend-env parms args env) cont))))) (t (interp-call x env cc))))))

Page 45: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun scheme (&optional x) "A Scheme read-eval-print loop (using interp). Handles call/cc by explicitly passing continuations." (init-scheme-interp) (if x (interp x nil #'print) (loop (format t "~&==> ") (interp (read) nil #'print))))

Page 46: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun interp-begin (body env cc) "Interpret each element of BODY, passing the last to CC." (interp (first body) env #'(lambda (val) (if (null (rest body)) (funcall cc val) (interp-begin (rest body) env cc)))))

(defun interp-call (call env cc) "Interpret the call (f x...) and pass the result to CC." (map-interp call env #'(lambda (fn-and-args) (apply (first fn-and-args) cc (rest fn-and-args)))))

(defun map-interp (list env cc) "Interpret each element of LIST, and pass the list to CC." (if (null list) (funcall cc nil) (interp (first list) env #'(lambda (x) (map-interp (rest list) env #'(lambda (y) (funcall cc (cons x y))))))))

Page 47: Introduction to Lisp For Scheme Users. What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions

(defun init-scheme-proc (f) "Define a Scheme primitive procedure as a CL function." (if (listp f) (set-global-var! (first f) #'(lambda (cont &rest args) (funcall cont (apply (second f) args)))) (init-scheme-proc (list f f))))

(defun call/cc (cc computation) "Make the continuation accessible to a Scheme procedure." (funcall computation cc ;; Package up CC into a Scheme function: #'(lambda (cont val) (declare (ignore cont)) (funcall cc val))))

;; Now install call/cc in the global environment(set-global-var! 'call/cc #'call/cc)(set-global-var! 'call-with-current-continuation #'call/cc)