Download presentation
Presentation is loading. Please wait.
Published byKristin Carson Modified over 9 years ago
1
© Kenneth C. Louden, 20031 Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden
2
Chapter 11 - Part IIIK. Louden, Programming Languages2 Recursive Functions Abstractly, a function f is a rule that associates to each x in some set X (the domain), a y in another set Y (the range): f: X Y. Alternatively, a function can be viewed as a subset S of the Cartesian product X Y with the property that (x,y), (x,y') S implies y = y'. Functions can be given as sets simply by listing their elements (definition by extension). More usually, functions are given by a formula (definition by comprension), which may or may not be recursive.
3
Chapter 11 - Part IIIK. Louden, Programming Languages3 Recursive Functions (2) Chapter 8 shows how to implement recursive functions. But how are such functions mathematically defined? One way to think abstractly about a recursive definition is to consider it to imply a (countably infinite) union of sets that are built, one element at a time, out of the base case or cases. Factorial example: fact n = if n = 0 then 1 else n * fact (n-1) The "base" point is (0,1): fact 0 = { (0,1) } Now consider the formula as a set equation: fact = fact 0 U fact', where fact' is the function formed for each n by the formula n * fact (n-1).
4
Chapter 11 - Part IIIK. Louden, Programming Languages4 Recursive Functions (3) Unfortunately, we don't yet know either fact or fact'. But consider what would happen if we used fact 0 as an approximation for fact in the formula for fact': fact 1 = fact 0 U fact 0 ', where fact 0 ' = { (n,m) | (n-1,p) fact 0, m = n*p } = { (1,1) } [since (1-1,1) = (0,1) fact 0 ] Then fact 1 = { (0,1) } U { (1,1) }. We have a new point! So apply the equation again, this time using fact 1 as an approximation for fact in fact'. We get yet another point! Call this function fact 2. Continue. Now let fact = U n = 1.. fact n. What function is this?
5
Chapter 11 - Part IIIK. Louden, Programming Languages5 Recursive Functions (4) If we try the process once again, we find that we get no new points: fact = fact 0 U fact '. The function fact is said to be a fixed point of the recursive equation for fact. Indeed, fact is the smallest such set with this property and is essentially unique. So it makes sense to define the fact function to be fact : we say that the recursive definition has least-fixed-point semantics. Not all sets allow least fixed point solutions to recursive equations. Sets that do are called domains. Domain theory tells us when recursive definitions will work (and when they won't).
6
Chapter 11 - Part IIIK. Louden, Programming Languages6 Fixed point In mathematics, a fixed point is a point that is mapped to itself by the function. For example, if f is defined in real number by f(x) = x 2 –3x + 4, then 2 is a fixed point of f, because f(2) = 2. Not all functions have fixed points: f(x)=x+1 has no fixed point on the reals.
7
Chapter 11 - Part IIIK. Louden, Programming Languages7 Factorial function fact n = if n = 0 then 1 else n * fact (n-1) f(n )= if n = 0 then 1 else n * g (n-1) Two parameters on the right: n and g We can think of this as defining a higher-order function H as follows H(g)(n) = if n = 0 then 1 else n * g (n-1) H (fact)(n) = fact(n)for all n Thus, the factorial function is a Fixed point of H!
8
Chapter 11 - Part IIIK. Louden, Programming Languages8 Least fixed point We want the smallest solution to this equation to be chosen definition of the fact function. For this reason, recursive function definitions are said to have least fixed point semantics, and fact is taken to be the least fixed point of the function H.
9
Chapter 11 - Part IIIK. Louden, Programming Languages9 Examples of least fixed points Page 89 Exp ->exp + exp|number E = E + E U N Page 523 fact = U n = 1.. fact n They are smallest solutions to the given set equetions!
10
Chapter 11 - Part IIIK. Louden, Programming Languages10 Lambda Calculus The lambda calculus is an abstraction and simplification of a functional programming language, much as a Turing machine is an abstraction and simplification of a computer. Lambda calculus is Turing-complete, so it it can be used as a model for computation instead of TMs. Issues such as delayed evaluation, recursion, and scope can be studied with mathematical precision in the lambda calculus.
11
Chapter 11 - Part IIIK. Louden, Programming Languages11 Syntax of Lambda Calculus Two sets of basic expressions: Variables: x,y,z, etc. (essentially identifiers representing parameters) Constants: numbers like 1, 2, 3; "built-in" functions like +, *, cons. Two operations: Abstraction (like lambda expressions in Scheme, ML, or Haskell - anonymous function creation). Application (like function call). Grammar: lexpr variable. lexpr | lexpr lexpr | ( lexpr ) | variable | constant abstractionapplication
12
Chapter 11 - Part IIIK. Louden, Programming Languages12 Example of Lambda Calculus Abstraction ( x. + 1 x) -- lambda abstraction This can be interpreted exactly as the lambda expression in Scheme (lambda (x) ( + 1 x) )
13
Chapter 11 - Part IIIK. Louden, Programming Languages13 Example of Lambda Calculus Application ( x. + 1 x) 2 => (+ 1 2) => 3 The basic operation of lambda calculus is the application of expression such as the lambda abstraction. The application of the function that adds 1 to x to the constant 2. Lambda calculus expresses this by providing a reduction rule that permits 2 to be substituted for x in the lambda (and removing the lambda) yielding the desired value.
14
Chapter 11 - Part IIIK. Louden, Programming Languages14 Examples of Lambda Calculus Expressions x. + (( y. ( x. x y) 2) x) y ( x. x y) y (( y. 2) (( x. x x) ( x. x x))) ( h. ( x. h (x x)) ( x. h (x x)))
15
Chapter 11 - Part IIIK. Louden, Programming Languages15 The notion of Currying Louden page 505-506 A function of multiple parameters that can be viewed as a (higher order) function of a single parameter that returns a function of the remaining parameters is said to be Curried. We will call a language fully Curried if function definitions are automatically treated as Curried.
16
Chapter 11 - Part IIIK. Louden, Programming Languages16 Notes Lambda calculus is fully Curried. Application works left to right, abstraction right to left. Application has higher precedence than abstraction. The set of variables is unspecified, but doesn't matter very much, as long as it is (countably) infinite. The set of constants isn't specified either, and this can make a difference in terms of what you want to express. This set may be infinite (all integers) or finite or even empty (pure lambda calculus). Thus, there are really many kinds of lambda calculus.
17
Chapter 11 - Part IIIK. Louden, Programming Languages17 Notes (continued) There are no semantic restrictions on the syntactically legal expressions in the lambda calculus: all expressions given by the syntax are legal. By the previous statement, there can be no type checking in the lambda calculus. There is in fact an alternate version called the typed lambda calculus that does have types. Not all lambda expressions make sense as programs: (x x) is legal, and so is (2 x). (Exercise: try typing x. x x in ML or Haskell.)
18
Chapter 11 - Part IIIK. Louden, Programming Languages18 Semantics of Lambda Calculus Some expressions are equivalent to others in lambda calculus even though they are syntactically distinct: x. x is equivalent to y. y( ) x. y x is equivalent to y ( ) ( x. x) y is equivalent to y( ) These equivalences have historical names: alpha-conversion ( -conversion), eta-conversion ( -conversion), and beta- conversion ( -conversion). When a conversion simplifies an expression it is called a reduction.
19
Chapter 11 - Part IIIK. Louden, Programming Languages19 Semantics (2) Conversion operations depend on the notion of the scope (or binding) of a variable in an abstraction. The variable x in the expression ( x.E) is said to be bound by the lambda. The scope of the binding is the expression E. An occurrence of a variable outside the scope of any binding of it by a lambda is a free occurrence. An occurrence that is not free is a bound occurrence. Thus, in the expression x. E, all occurrences of x in E are bound.
20
Chapter 11 - Part IIIK. Louden, Programming Languages20 Examples of bound and free vars: In the expression ( x. x y) y the variable x is bound and both instances of the variable y are free. In the expression x. + (( y. ( x. x y) 2) x) y both instances of x are bound (but by different lambdas), and the first instance of y is bound, while the second one is free (arrows point to bindings): x. + (( y. ( x. x y) 2) x) y
21
Chapter 11 - Part IIIK. Louden, Programming Languages21 Conversion Rules First, let E[F/x] represent the expression obtained by substituting all free occurrences of x by F in the expression E. -conversion: x. E is equivalent to y. E[y/x], provided E contains no free occurrences of y. -conversion: ( x. E) F is equivalent to E[F/x], provided F contains no free variables that are bound in E. -conversion: x. E x is equivalent to E, provided E contains no free occurrences of x.
22
Chapter 11 - Part IIIK. Louden, Programming Languages22 Name Capture Each of the above rules has a side condition which represents a name capture issue: if you substitute an expression with free variables into a lambda, one or more of those free variables may conflict with names bound by lambdas (and be captured by them), giving incorrect results (since variable bound/free status should not change): ( ) : x. y y. y ( ) : ( x. y. x y) y y. y y ( ) : x. x x x
23
Chapter 11 - Part IIIK. Louden, Programming Languages23 Name Capture (2) The solution is to use -conversion to change bound variable names that clash with free variables in -reduction: ( x. y. x y) y = ( x. z. x z) y = z. y z In the other two cases, we simply cannot perform that particular conversion.
24
Chapter 11 - Part IIIK. Louden, Programming Languages24 Semantics (3) An expression is a normal form if there are no -reductions that can be performed on it. The semantics of an expression in lambda calculus is expressed by converting it to a normal form, if possible. Such a normal form, if it exists, is unique, by the famous Church-Rosser Theorem. Not all reduction sequences lead to a normal form: ( y. 2) (( x. x x)( x. x x))
25
Chapter 11 - Part IIIK. Louden, Programming Languages25 Normal vs. Applicative Order A -reduction ( x. E) F => E[F/x] that substitutes F for x before reducing F is called a normal-order reduction. It corresponds to the lazy evaluation of Haskell (without the memoization). If on the other hand, the -reduction ( x. E) F => E[F/x] is performed only after reducing F, it is called an applicative order reduction. This corresponds to the evaluation rule of Scheme, where all arguments are evaluated before a call.
26
Chapter 11 - Part IIIK. Louden, Programming Languages26 Semantics (4) Main result (also a consequence of the Church-Rosser Theorem): if a normal form exists, a normal-order sequence of conversions will find it. Example 1: a normal form for ( y. 2) (( x. x x)( x. x x)) is 2, but an applicative-order -reduction gets into an infinite loop. Example 2: x. + (( y. ( x. x y) 2) x) y reduces to x. + ( 2 x) y using either normal-order or applicative-order.
27
Chapter 11 - Part IIIK. Louden, Programming Languages27 Recursion Can recursion be expressed in lambda calculus? Note that lambda calculus has no mechanism for resolving free names, which is the usual way of expressing recursion: fact = n.if n==0 then 1 else n*fact(n-1) To get rid of the free name in the right-hand side, make it a parameter: H fact = g. n.if n==0 then 1 else n*g(n-1) Now if H fact f = f, then f must be fact ! Such an f is called a fixed point of H fact. Is there a lambda expression that can produce fixed points? YES!
28
Chapter 11 - Part IIIK. Louden, Programming Languages28 Recursion (2) The lambda expression Y = h.( x. h (x x))( x. h (x x)) produces arbitrary fixed points: let H be any lambda expression. Then Y H = ( x. H (x x))( x. H (x x)) = H (( x. H (x x)) ( x. H (x x))) = H (Y H), so Y H is a fixed point of H. Unfortunately, Y has no type in ML or Haskell (try it!), but we can fall back on the fixed point property itself as a definition of Y, in either ML, Haskell, or Scheme: y h = h (y h) To what extent this works in the actual languages is Exercise 11.50.
29
Chapter 11 - Part IIIK. Louden, Programming Languages29 Implementing standard language features in lambda calculus Recursion can be implemented (as we have just seen). So can numbers (Exercise 11.47). So can lists (Exercise 11.46). So can Booleans and if-then-else: true = x. y. x, false = x. y. y, if = x. y. z. x y z, and now (if true E F) = E and (if false E F) = F Indeed, everything can (with some huffing and puffing, as with Turing Machines)!
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.