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

Slides:



Advertisements
Similar presentations
09 Examples Functional Programming. Tower of Hanoi AB C.
Advertisements

C-LISP. LISP 2 Lisp was invented by John McCarthy in 1958 while he was at the Massachusetts Institute of Technology (MIT).John McCarthyMassachusetts Institute.
Scheme in Scheme. Why implement Scheme in Scheme  Implementing a language is a good way to learn more about programming languages  Interpreters are.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
1 Programming Languages and Paradigms Lisp Programming.
Chapter 3 Functional Programming. Outline Introduction to functional programming Scheme: an untyped functional programming language.
1 Introduction of Lisp function e.g. (+ 2 2) Shift+Enter Execute …… (+ 1 2) 3 ( ) 15 (- 1 6) -5 ( ) -5 (- ( ) (+
Lisp – Introduction יעל נצר מערכות נבונות סמסטר ב' תשס"ו.
Prof. Fateman CS164 Lecture 241 Other Control Flow ideas: Throw, Catch, Continuations and Call/CC Lecture 24.
Introduction to Artificial Intelligence Lisp Ruth Bergman Fall 2002.
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
CSE S. Tanimoto Macros 1 Defining Macros in Lisp Extensibility: A language is extensible if the language can be extended. New Lisp control structures.
CMSC 471 LISP. Why Lisp? Because it’s the most widely used AI programming language Because it’s good for writing production software (Graham article)
CSE S. Tanimoto Explicit Function Application 1 Explicit Application of Functions, Functional Arguments and Explicit Evaluation Implicit and explicit.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
LISP A brief overview. Lisp stands for “LISt Process” –Invented by John McCarthy (1958) –Simple data structure (atoms and lists) –Heavy use of recursion.
COMP 205 – Week 11 Dr. Chunbo Chu. Intro Lisp stands for “LISt Process” Invented by John McCarthy (1958) Simple data structure (atoms and lists) Heavy.
LISP 1.5 and beyond A very quick tour. Data Atoms (symbols) including numbers – All types of numbers including Roman! (well, in the early days) – Syntactically.
TUTORIAL 2 CSCI3230 ( First Term) By Paco WONG 1.
F UNCTIONAL P ROGRAMMING 05 Functions. F UNCTIONS - G LOBAL F UNCTIONS fboundp Tells whether there is a function with a given symbol as its name > (fboundp.
The Case primitive: matches the evaluated key form against the unevaluated keys by using eql The general format of case is the following: (case (... ).....
For Monday Read Chapter 3 Homework: –Lisp handout 2.
1 Lisp Functions –Built-in functions –Defining functions –Function Evaluation and Special Forms defun, if Control statements –Conditional if, cond –Repetition.
Lecture 2-1CS250: Intro to AI/Lisp Intelligent Agents Lecture 3-2 October 14 th, 1999 CS250.
ISBN Chapter 15 Functional Programming Languages.
Functional Programming in Scheme and Lisp. Overview In a functional programming language, functions are first class objects. You can create them, put.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
The Loop Macro Many of the CL “functions” are actually macros (let, progn, if, etc) The most complicated macro in CL is probably the Loop macro –The Loop.
Lecture 6-2CS250: Intro to AI/Lisp Programming in Your Favorite Language Lecture 5-2 February 11 th, 1999 CS250.
CSE S. Tanimoto Lisp Defining Macros in Lisp Extensibility: A language is extensible if the language can be extended. New Lisp control structures.
Lisp Files, Arrays, and Macros CIS 479/579 Bruce R. Maxim UM-Dearborn.
Introduction to ACL2 CS 680 Formal Methods for Computer Verification Jeremy Johnson Drexel University.
LISP Data Types Functional Programming Academic Year Alessandro Cimatti
Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments.
Introduction to LISP. Lisp Extensible: It lets you define new operators yourself Lisp programs are expressed as lisp data structures –You can write programs.
UMBC CMSC Common Lisp II. UMBC CMSC Input and Output Print is the most primitive output function > (print (list 'foo 'bar)) (FOO BAR) The.
CSE S. Tanimoto Macros 1 Defining Macros in Scheme Extensibility: A language is extensible if the language can be extended. New Scheme control structures.
Milos Hauskrecht (PDF) Hieu D. Vu (PPT) LISP PROGARMMING LANGUAGE.
1 Variable Declarations Global and special variables – (defvar …) – (defparameter …) – (defconstant …) – (setq var2 (list 4 5)) – (setf …) Local variables.
Basic Introduction to Lisp
Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning
Scheme in Scheme 2. What’s next  Adding set!  Dynamic vs. lexical variable scope  Extending mcscheme v1 with libraries  Can mcscheme execute mcscheme?
CSE 341, S. Tanimoto Lisp Explicit Application of Functions and Functional Arguments In Lisp, functions can be passed as arguments to other functions.
1 Outline Review Introduction to LISP Symbols and Numbers Lists Writing LISP Functions LISPWorks.
Section 15.4, 15.6 plus other materials
Defining Macros in Lisp
Example of formula (defun roots (a b c) (list
Modern Programming Languages Lecture 20 Fakhar Lodhi
Getting Started with Lisp
Env. Model Implementation
LISP A brief overview.
Nondeterministic Evaluation
Dynamic Scoping Lazy Evaluation
Modern Programming Languages Lecture 20 Fakhar Lodhi
The Metacircular Evaluator (Continued)
CSE S. Tanimoto Explicit Function Application
Lisp: Using Functions as Data
LISP A brief overview.
John McCarthy Pioneer in AI Also Lisp Formalize common-sense reasoning
Defining Macros in Lisp
Defining Functions with DEFUN
Abstraction and Repetition
Lisp: Using Functions as Data
Modern Programming Languages Lecture 18 Fakhar Lodhi
Common Lisp II.
Defining Macros in Scheme
The general format of case is the following: (case <key form>
List manipulation Consider student database, where each student is represented by the following list: * (setf student1 '((Paul Bennett) ((hw1 4.3) (hw2.
Presentation transcript:

Introduction to Lisp For Scheme Users

What Makes Lisp Different? Built-in Support for Lists Automatic Storage Management Dynamic Typing First-Class Functions Uniform Syntax Interactive Environment Extensibility History

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.

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.

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)

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

Scheme vs. Lisp (3) set! set-car! vector-set! string-set! setq, setf replaca, setf setf

Parameters in Scheme (define (foo-1 arg1. rest) body) (define (bar arg1 arg2) body) ( foo ) arg1  1 rest  ( ) (foo-1 1) arg1  1 rest  () (bar 1 2)

Parameters in Lisp (defun foo-1 (arg1 &rest rest) body) (defun foo-2 (arg1 &optional (arg2 default-value)) body) (foo ) arg1  1 rest  ( ) (foo ) arg1  1 rest  ( ) (foo-2 2) arg1  2 arg2  default-value (foo-2 2 3) arg1  2 arg2  3

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

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)))

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)))

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

A Scheme Interpreter (2) set-var! get-var set-global-var! get-global-var extend-env init-scheme-interp init-scheme-proc Auxiliary Functions Set a variable to a value Get the value of variable in an environment Set a global variable to a value Get the value of a variable from the global environment Add some variables and values to an environment Initialize some global variables Define a primitive Scheme procedure

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

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?

A Basic Scheme Interpreter 1.If the expression is a symbol, look up its value in the environment 2.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 expression 4.If it starts with begin, interpret each subexpression, and return the last one 5.If it starts with set!, interpret the value and then set the variable to that value 6.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-part 7.If it starts with lambda, build a new procedure – a closure over the current environment 8.Otherwise, it must be a procedure application. Interpret the procedure and all it arguments, and apply the procedure value to the argument values

(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))))))))

(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)))

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

(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))))

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

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 …)

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

Macro Evaluation Expansion, e.g.  (schema-macro-expand ‘(let ((x 1) (y 2)) (+ x y))) ((lambda (x y) (+ x y)) 1 2) Evaluation

(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))))))))

(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))

(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))))))))

(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)) #'(lambda (clause) (if (starts-with clause 'else) clause `((member,key-val ',(first clause)).,(rest clause)))) clauses)))))

(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)) #'(lambda (v) `(set!.,v)) bindings).,body))

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))))

(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

((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))))))))))

(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) '??)))

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 ’( x 10 20)) 1, 2, 3, “huh?”

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 ’( x 10 20)) 1, 2, 3, “huh?”

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.

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))

Continuations in Scheme (3) In Scheme, every expression has a continuation and the evaluator always has a function at hand 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, and it immediately call this function thereby passing it the continuation of the entire call/cc expression.

A Continuation Example (define aFuture '()) (display (+ 2 (call/cc (lambda (cont) (set! aFuture cont) 8))))

Another Continuation Example: Error handling (define error '()) (call/cc (lambda (cont) (set! error cont) (p)))

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)))

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))))

(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))))))

(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))))

(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))))))))

(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)