220 likes | 363 Views
Chapter 11 - Functional Programming, Part III: Theory. Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden. Recursive Functions.
E N D
Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden © Kenneth C. Louden, 2003
Recursive Functions • Abstractly, a functionf is a rule that associates to each x in some set X (the domain), a y in another set Y (the range): f: XY. • 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. K. Louden, Programming Languages
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): fact0 = { (0,1) } • Now consider the formula as a set equation:fact = fact0 U fact', where fact' is the function formed for each n by the formula n * fact (n-1). K. Louden, Programming Languages
Recursive Functions (3) • Unfortunately, we don't yet know either fact or fact'. • But consider what would happen if we used fact0 as an approximation for fact in the formula for fact': • fact1 = fact0 U fact0' , where fact0' = { (n,m) | (n-1,p) fact0 , m = n*p } = { (1,1) } [since (1-1,1) = (0,1) fact0] • Then fact1 = { (0,1) } U { (1,1) }. We have a new point! • So apply the equation again, this time using fact1 as an approximation for fact in fact'. We get yet another point! Call this function fact2 . Continue. • Now let fact = Un = 1.. factn . What function is this? K. Louden, Programming Languages
Recursive Functions (4) • If we try the process once again, we find that we get no new points: fact = fact0 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). K. Louden, Programming Languages
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. K. Louden, Programming Languages
abstraction application 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:lexprvariable.lexpr | lexpr lexpr | (lexpr ) | variable | constant K. Louden, Programming Languages
Examples of Lambda Calculus Expressions • x . + ((y. (x. x y) 2) x) y • (x . xy) y • ((y. 2) ((x. x x) (x. x x))) • (h. (x. h (x x)) (x. h (x x))) K. Louden, Programming Languages
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. K. Louden, Programming Languages
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.) K. Louden, Programming Languages
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. K. Louden, Programming Languages
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) issaid 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. K. Louden, Programming Languages
Examples of bound and free vars: • In the expression (x . xy) 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 K. Louden, Programming Languages
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. K. Louden, Programming Languages
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 K. Louden, Programming Languages
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. K. Louden, Programming Languages
Semantics (3) • An expression is a normal formif 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. xx)( x. xx)) K. Louden, Programming Languages
Normal vs. Applicative Order • A -reduction ( x. E) F => E[F/x]that substitutes F for xbefore 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. K. Louden, Programming Languages
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. xx)( x. xx)) 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. K. Louden, Programming Languages
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:Hfact = g.n.if n==0 then 1 else n*g(n-1) • Now if Hfact f = f, then f must be fact! Such an f is called a fixed point of Hfact. • Is there a lambda expression that can produce fixed points? YES! K. Louden, Programming Languages
Recursion (2) • The lambda expression Y = h.(x. h (xx))(x. h (xx)) produces arbitrary fixed points: let H be any lambda expression. ThenY H = (x. H (xx))(x. H (xx)) = H ((x. H (xx)) (x. H (xx))) = 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. K. Louden, Programming Languages
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 EF) = F • Indeed, everything can (with some huffing and puffing, as with Turing Machines)! K. Louden, Programming Languages