λ Calculus Basis Lambda Calculus and Lambda notation in Lisp II Based on Prof. Gotshalks notes on Lambda Calculus and Chapter 9 in Wilensky Mathematical theory for anonymous functions» functions that have not been bound to names Present a subset of full definition to present the flavour Notation and interpretation scheme identifies» functions and their application to operands > argument-parameter binding» Clearly indicates which variables are free and which are bound LC2-1 LC2-2 Bound and Free Variables Bound variables are similar to local variables in Java function (or any procedural language)» Changing the name of a bound variable (consistently) does not change the semantics (meaning) of a function Free variables are similar to global variables in Java function (or any procedural language)» Changing the name of a free variable normally changes the semantics (meaning) of a function. { λ u, w. ( u + 1 ) ( v 1 ) ( w + 2 ) } bound variables In the above λ expression:» u and w are bound» v is free λ functions defining form LC2-3 LC2-4
Work from the inside out Function application Work right to left so arguments are evaluated first λ function example { λ u, v. ( u * v) / ( u + 6 ) } [ { λ a. a ( a + 1 ) } [ 3 ], { λ b. ( b + 1 )**2 } [ 2 ] ] Build up longer definitions with auxiliary definitions { λ u, v. ( u * v) / ( u + 6 ) } [ 12, { λ b. ( b + 1 )**2 } [ 2 ] ] { λ u, v. ( u * v) / ( u + 6 ) } [ 12, 9 ] 108/18 6 LC2-5 LC2-6 λ function example { λ f. f * (f + 1) } [ { λ a, b. a ( b + 1 ) } [ x + 1, x - 1 ] ] { λ f. f * (f + 1)} [ (x+1) * x ] λ function example - 1 Example» Define f(u(a)) = u(a)**2+1 where u(a) = a ( a + 1 ) where a = z+1 where z = 1 (x+1)*x*((x+1)*x+1) x * (x+1) * (x**2+x+1) LC2-7 LC2-8
λ function example - 2 Example» Define f(u(a)) = u(a)**2+1 where u(a) = a ( a + 1 ) where a = z+1 where z = 1 λ function example - 3 Example» Define f(u(a)) = u(a)**2+1 where u(a) = a ( a + 1 ) where a = z+1 where z = 1 { λ z. z + 1 } [ 1 ] { λ a. a ( a + 1 ) } [ { λ z. z + 1 } [ 1 ] ] LC2-9 LC2-10 λ function example - 4 Example» Define f(u(a)) = u(a)**2+1 where u(a) = a ( a + 1 ) where a = z+1 where z = 1 λ function example - 5 Example» Define f(u(a)) = u(a)**2+1 where u(a) = a ( a + 1 ) where a = z+1 where z = 1 { λ f. f ** 2 + 1 } [ { λ a. a ( a + 1 ) } [ { λ z. z + 1 } [ 1 ] ] ] { λ f. f ** 2 + 1 } [ { λ a. a ( a + 1 ) } [ { λ z. z + 1 } [ 1 ] ] ] { λ f. f ** 2 + 1 } [ { λ a. a ( a + 1 ) } [ 2 ] ] { λ f. f ** 2 + 1 } [ 6 ] 37 LC2-11 LC2-12
Lambda functions in Lisp Lambda functions in Lisp are anonymous functions or functions without a name. Eliminate the need to allot a function storage space Use lambda functions when you don t expect to reuse the function Lambda functions can be found wherever Lisp expects to find a function All Lisp functions are stored as lambda functions Lamba notation in Lisp Lambda expressions are a direct analogue of λ-calculus expressions» They are the basis of Lisp functions a modified syntax to simplify the interpreter For example ( defun double ( x ) ( + x x ) ) > is the named version of the following unnamed lambda expression ( lambda ( x ) ( + x x ) ) { λ x. ( x + x ) } > Note the similar syntax with λ-calculus and the change to prefix, from infix, to permit a uniform syntax for functions of any number of arguments LC2-13 LC2-14 Lambda expression - 1 ( lambda ( list of symbols ) list of forms ) list of symbols: list of formal parameters Lambda expression - 2 We are used to seeing functions at the beginning of a list followed by arguments. Lambda functions can be used the same way. ( (lambda ( list of symbols ) list of forms ) arguments ) list of forms: body of the function list of symbols: list of formal parameters list of forms: body of the function arguments: arguments supplied to lambda function LC2-15 LC2-16
Lambda examples > ( ( lambda ( x ) (cons x nil ) ) y) (Y) > ( apply ( lambda ( x y ) ( list y x ) ) ( 1 2 ) ) ( 2 1 ) > ( mapcar ( lambda ( x ) ( / 1 ( sqrt x ) ) ) ( 1 2 3 4 5 ) ) ( 1.0 0.707106 0.577350 0.5 0.447213 ) > ( ( lambda ( x ) ( setq x 5 ) ) ( setq x 4 ) ) 5 > x 4 More lambda examples > ( apply ( lambda ( x y ) ( list y x ) ) ( ( list 1 2 3 ) car ) ) ( CAR ( LIST 1 2 3 )) > ( funcall ( lambda ( x y ) ( list y x ) ) ( list 1 2 3 ) car ) ( CAR ( LIST 1 2 3 )) > ( eval ( ( lambda ( x y ) ( list y x ) ) (list 1 2 3 ) car ) ) 1 > ( eval ( funcall ( lambda ( x y ) ( list y x ) ) ( list 1 2 3 ) car ) ) 1 LC2-17 LC2-18 Even more lambda examples > ( mapcar ( lambda ( x ) ( list a x ) ) ( 1 2 3 ) ) ( ( A 1 ) ( A 2 ) ( A 3 ) ) > ( mapc ( lambda ( x ) ( + x x ) ) ( 1 2 3 ) ) ( 1 2 3 ) > ( mapcar ( lambda ( x ) ( or ( atom x ) ( equal ( a b ) x ) ) ) ( a b ( a b ) ( ) x ( ( x ) ) ) ) Remember sumint sumint (defun sumint (func n) (cond ((equal n 0) 0) ( t ( + (funcall func n) (sumint func (1- n)))))) ( T T T T T NIL ) > ( maplist ( lambda (x) ( cons (car x) ( b ) ) ) (1 2 3 ) ) ( ( 1 B ) ( 2 B ) ( 3 B ) ) LC2-19 LC2-20
Anonymous functions - 1 Recall in the abstraction for sumint we defined support functions to handle each case (defun double (int) (+ int int)) (defun square (int) (* int int)) (defun identity (int) int) Then we called sumint with the desired function as an argument (sumint double 10 ) -- > 110 (sumint square 2 ) -- > 5 (sumint identity 5 ) -- > 15 Anonymous functions - 2 This adds additional symbols we may not want, especially if the function is to be used only once. Using lambda we get the same effect without adding symbols (sumint # (lambda (int) (+ int int)) 10) (sumint # (lambda (int) (* int int)) 10) (sumint # (lambda (int) int) 10) LC2-21 LC2-22 The function 'function' What is the meaning of # in the following (sumint # (lambda (int) (+ int int)) 10) It is a short hand» # (...) ==> (function (...)) One of its attributes is it works like quote, in that its argument is not evaluated, thus, in this simple context the following will also work (sumint (lambda (int) (+ int int)) 10) Later we will see another attribute of function that makes it different from quote. Another example - 1 Suppose we have a two step process we want to apply when iterating down a list. For example: we first want to take the absolute value of each number and then we want to take the square root. Applying these operations to the list (1-4 16-25) would produce (1 2 4 5). Whenever a function is to be quoted use # in place of LC2-23 LC2-24
Another example - 2 We could accomplish this by using functionals: Another example - 3 We could accomplish this by using functionals: (???? # sqrt (???? # abs ( -9 16 1024-1 ) ) ) (???? # sqrt (mapcar # abs ( -9 16 1024-1 ) ) ) LC2-25 LC2-26 Another example - 4 We could accomplish this by using functionals: Another example - 5 A different way to accomplish the same thing: ( mapcar # sqrt (mapcar # abs ( -9 16 1024-1 ) ) ) ( defun compose ( f g ) # ( lambda ( x ) ( funcall f (funcall g x ) ) ) ) NOTE: instead of passing a function into a function, here you are passing a function out of a function LC2-27 LC2-28
Another example - 6 A different way to accomplish the same thing: > ( mapcar # sqrt (mapcar # abs ( -9 16 1024-1 ) ) ) ( 3.0 4.0 32.0 1.0 ) > ( funcall (compose # sqrt # abs ) -9 ) 3.0 > ( mapcar (compose # sqrt # abs ) ( -9 16 1024-1 ) ) ( 3.0 4.0 32.0 1.0 ) Note: this gets rid of the nested mapcars Recursion Recursion with lambda functions uses labels to temporarily name a function The following is a general λ-calculus template. > The name is in scope within the entire body but is out of scope outside of the lambda expression. { label name ( lambda arguments. body_references_name ) } In Lisp can use labels to define a mutually recursive set of functions ( labels (list of named lambda expressions) sequence of forms using the temporarily named functions ) LC2-29 LC2-30 Example 1 of recursion A recursive multiply that uses only addition. > The temporary function is called mult (labels ((mult (k n) (cond ((zerop n) 0) (t (+ k (mult k (1- n)))) ))) (mult 2 3) ) Example 2 of recursion rectimes computes k * n by supplying the parameters to a unary function that is a variation of example 1. (defun rectimes (k n) )) (labels (( temp (n) ))) (temp n) (cond ((zerop n) 0) ( t (+ k (temp (1- n)))) LC2-31 LC2-32
A Lisp hackers puzzle A Lisp hackers puzzle Self replicating So t No good must be non-atomic Generate a self-reproducing non-atomic Lisp form??? It is considered cheating if your form involves any permanent side-effects. How about creating a function foo that returns foo Also no good - creating a function involves a permanent sideeffect. All known solutions involve using lambda! LC2-33 LC2-34 A Lisp hackers puzzle TEST 1 A solution: ( ( lambda ( x ) ( list ( list lambda ( x ) x ) ( list quote x ) ) ) ( list ( list lambda ( x ) x ) ( list quote x ) ) ) ) TEST 1 WILL COVER ALL MATERIAL UNTIL HERE!! LC2-35 LC2-36
TEST 1 What is on the test?» All my slides» Wilensky chapters 1, 2, 3, 15, 4, 6, 7, 8, 9 (not 9.6)» Notes on symbols, notes on functionals (no Backus notation), notes on lambda calculus > Notes are on the web site under resources LC2-37