Functional programming: LISP
description
Transcript of Functional programming: LISP
![Page 1: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/1.jpg)
Functional programming: LISP
• Originally developed for symbolic computing• First interactive, interpreted language• Dynamic typing: values have types, variables do not• Garbage-collected • Homogeneity of program and data• Extensible: multiple dialects, implementations.
Convenient testbed for language design experiments• Main descendants: Scheme (compact) Common Lisp
(massive). Statically typed functional languages: ML
![Page 2: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/2.jpg)
Uniform syntax: lists
• Expressions are either atoms or lists• atoms are numeric or symbols• lists nest, to form full trees• Syntax is simple because programmer supplies what
would otherwise be the internal representation of a program:
(+ ( * 10, 12) (* 7, 11)) evaluates (10*12 + 7*11)• A program is a list:
(define (factorial n) (if (eq n 0) 1
( * n (factorial (- n 1))))
![Page 3: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/3.jpg)
List manipulation
• Three primitives and one constant– get head of list: car– get rest of list: cdr– add an element to a list: cons– null list: nil or ( )
• Add equality ( = or eq) and recursion, and this is a universal model of computation
![Page 4: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/4.jpg)
Rule of evaluation
• A number evaluates to itself• An atom evaluates to its current binding• A list is a computation.
– Its first element must evaluate to an operation– the remaining elements are actual parameters– the result is the application of the operation to the
evaluated actuals
![Page 5: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/5.jpg)
Quoted data
• If every list is a computation, how do we describe data?
• Another primitive: quote
(quote (1 2 3 4))
=> (1 2 3 4)
(quote (this is a simple declarative sentence)
=> (this is a simple declarative sentence)
‘ (this also works)
=> (this also works)
![Page 6: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/6.jpg)
Decomposing a list
(car ‘(this is a list of symbols))
=> this
(cdr ‘(this is a list of symbols))
=> (is a list of symbols)
(cdr ‘(this that))
=> (that) ; a list (cdr ‘(singleton))
=> ( ) ; the empty list
(car ‘( )) ; run time error
![Page 7: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/7.jpg)
Building lists
(cons ‘this ‘(that and the other))
=> (this that and the other)
(cons ‘a ‘( ))
=> (a)
useful shortcut: list
(list ‘a ‘b ‘c ‘d ‘e)
=> (a b c d e)
equivalent to
(cons ‘a (cons ‘b (cons ‘c (cons ‘d (cons ‘e ‘( ))))))
![Page 8: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/8.jpg)
Control structures
• Conditional
(if condition expr1 expr2)• Generalized form
(cond
(pred1 expr1)
(pred2 expr2)
…
(else exprn)
Needs special rule: evaluate only the successful entry
if and cond are not regular functions
![Page 9: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/9.jpg)
Function declarations
(define (sqr n) (* n n))• define is also special: body is not evaluated• define produces a binding: sqr is bound to the body
of the computation:
(lambda (n) (* n n))• define can produce value bindings as well:
(define x 15)
(sqr x)
=> 225
![Page 10: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/10.jpg)
Recursion
(define (add1 x) (+ x 1)) ; the beginnings of Peano arithmetic
(define (sub1 x) (- x 1))
(define (add x y)
(if (= y 0) x
(add (add1 x) (sub1 y)))
(define (times x y)
(cond
((= y 0) 0)
((= y 1) x)
(else (add x (times (x (sub1 y)))))))
![Page 11: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/11.jpg)
Recursion (ii)
(define (exp x y)
(cond
((eq y 0) 1)
(else (times x (exp x (sub1 y))))))
better:
(define (fast-exp x y)
(cond (= y 0) 1)
( (even? y) (square (fast-exp x (/ y 2))))
(else (* x (fast-exp x (- y 1))))))
(define (even? n) (= (remainder n 2) 0)) ; a predicate
![Page 12: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/12.jpg)
Recursion on lists
(define (member elmt lis)
(cond
((null? lis) ‘())
((eq elmt (car lis)) lis)
(else (member elmt (cdr lis)))))
convention: return rest of list, starting from elmt, rather than #t or #f
convention: every non-false value is true in a boolean context
![Page 13: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/13.jpg)
Predicates
• If variables are untyped, need run-time tests to determine kind:
symbol?
number?
list?
null?
zero?
Syntax conventions differ in different dialects: symbolp, numberp, listp, zerop...
![Page 14: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/14.jpg)
Functional arguments
(define (map fun lis)
(cond
((null? lis) ‘())
(cons (fun (car lis)) (map fun (cdr lis)))))
(map sqr (map sqr ‘( 1 2 3 4))
=> (1 16 81 256)
![Page 15: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/15.jpg)
Self-definition
(define (eval exp env) ; the lisp interpreter
(cond
((number? exp) exp) ; numbers are self-evaluating
((symbol? exp) (lookup exp env)) ; a symbol has a binding
((null? exp) ‘())
((eq (car exp) ‘quote) (car (cdr exp))) ; could write cadr
((eq (car exp) ‘car) (car (car (cdr exp)))) ; caadr
((eq (car exp) ‘cdr) (cdr (car (cdr exp)))) : cdadr
(else (apply (eval (car exp) env) ; apply function
(eval-list (cdr exp) env))) ; to arguments
![Page 16: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/16.jpg)
Function application
(define (apply procedure arguments)
(eval (procedure-body procedure)
(extend-environment
(parameters procedure)
arguments
(environment procedure))))
In words: add actuals to environment, evaluate body of procedure in new environment
Note: environment is part of procedure definition (closure)
![Page 17: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/17.jpg)
Environments
• An environment describes the current bindings of symbols
• A binding is a pair: (symbol value)• A frame is a list of bindings (activation record), i.e. an
association list: ((s1 v1) (s2 v2)…)• An environment is a list of frames• In some cases we can treat the environment as a
single association list (e.g. with dynamic binding)
![Page 18: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/18.jpg)
Association lists
(define (add-assoc symb val env)
(cons (list symb val) env)) ; add a binding
(define (name binding) (car binding)) ; for readability
(define (value binding) (car (cdr binding)));
(define (lookup symb env) ; sequential search
(cond
((null? env) ‘()) ; error detected later
((eq symb (name (car env))) (value (car env))
(else (lookup symb (cdr env)))))
![Page 19: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/19.jpg)
Procedures and their environment
• A function has three components: a list of formals, a body, and environment of definition. Formals and body are represented by a lambda expression:
(lambda (f1 f2 ..) expr)• A function is evaluated in its environment of definition
(lexical scoping) after adding the current bindings of the actuals (activation record)
• The definition must capture all three components
(define (make-procedure spec body env)
(list ‘procedure (make-lambda spec body) env))
make-procedure is called by eval to evaluate a define
![Page 20: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/20.jpg)
Procedure components
given the representation
(procedure (lambda parameters body) env)
the components of a procedure can be obtained as follows:
(define (parameters proc) (cadr (cadr proc)))
(define (procedure-body proc) (caddr (cadr proc)))
(define (environment proc) (caddr proc))
![Page 21: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/21.jpg)
Evaluating a function definition
(define (name binding) (car binding))• results in the binding:
(name
(procedure (lambda (binding) (car binding)) env))
• procedure and lambda are labels to indicate kind• Env is the current environment. At the top level it
includes the binding for car (used in the body) as well as all other predefined symbols.
![Page 22: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/22.jpg)
The need for closure
(define (compose f1 f2)
(lambda (x) (f1 (f2 x))))
(define (sqr x) (* x x))
(define fourth (compose (sqr sqr)))
(fourth 4) ; yields 256
When fourth is called, the bindings of f1 and f2 have
disappeared. The evaluation of the lambda captures the environment in which f1 and f2 are bound to sqr.
![Page 23: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/23.jpg)
Binding formals to actuals
(define (make-frame formals actuals)
(cond
(null? formals) ‘()) ; should check (null? actuals) also
( else (cons
(add-assoc (car formals) (car actuals))
(make-frame (cdr formals) (cdr actuals))))))
(define (extend-environment formals actuals env)
(cons (make-frame formals actuals) env)
![Page 24: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/24.jpg)
Dynamic binding
• Alternative definition for free variables: use most recent binding for that symbol. Useful in cases such as:
(define (sum fun a next b)
(if ( > a b) 0
(+ (fun a) (sum fun (next a) b))))
(define sum-powers a b n)
(sum nth-power a incr b)
; could write (sum nth-power (lambda (x) (+ x 1)) b)
(define (nth-power x) (expt x n)) ;; WHAT N? ; n undefined if static binding.
; Bound in sum-powers if dynamic binding.
![Page 25: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/25.jpg)
Implementing dynamic binding
• Change eval to pass current environment to apply• change apply to use current environment rather than
procedure environment: Eval: ... (else (apply
(eval (car exp) env) ; apply function
(eval-list (cdr exp) env) ; to arguments
env)) ; in current env
Apply: (eval (procedure-body procedure)
(extend-environment ; add bindings
(parameters procedure) ; of formals
arguments
env))) ; to current env
![Page 26: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/26.jpg)
Other binding constructs
• Local variables
(let
((x 5) (y 10)) ; x and y bound simultaneously
(* x y))
(let*
((x 5) (y (expt x 2)) ; sequential bindings: y after x
(* x y 3))
![Page 27: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/27.jpg)
Tail recursion
• Tail recursive function needs single stack frame. mandated by semantics of Scheme:
(define (factorial n) (if (zero? N) 1)
(* n (factorial (- n 1))) ; stack grows to size n
define factorial n) (fact-iter 1 1 n) ; alternate definition
(define (fact-iter prod count var)
(if (> count var) prod
(fact-iter (* count prod) ; tail recursion
(+ count 1) ; implemented as loop
var))))
![Page 28: Functional programming: LISP](https://reader036.fdocuments.us/reader036/viewer/2022062409/56814eab550346895dbc56fd/html5/thumbnails/28.jpg)
Implementation of tail recursion
• If last operation in function is recursive call, overwrite actuals and go to beginning of code:
(define (last lis)
(if (null? (cdr lis) (car lis))
(last (crd lis)))) ; can be done with loop
(define (length lis)
(if (null? lis) 0)
(+ 1 (length (cdr lis)))) ; not tail recursive!