introduction to the l-calculusmainpage.nwu.edu.cn/hkg/docs/pi/cs345-lecture-05.pdf · nj. hartley...
TRANSCRIPT
Introduction to the l-calculus
CS345 - Programming Languages
Dr. Greg LavenderDepartment of Computer SciencesThe University of Texas at Austin
10/1/03 07:21 CS345 - Programming Languages 2
l-calculus in Computer Science
n a formal notation, theory, and model of computationn Church’s thesis => l-calculus is equivalent to Turing Machines
n equivalence was proved by Kleene
n foundation for the functional style of programmingn ISWIM, Lisp, Scheme, ML, Haskell, …
n natural model for many computational objectsn higher-order functions, variables, block scopes, expressions,
ordered pairs, lists, records, recursionn calling conventions: call-by-value, call-by-need, call-by-name
n type inferencing & polymorphic type systemsn Roger Hindley & Robin Milner (Turing award)
n notation for Scott-Strachey denotational semanticsn Domain theory of Dana Scott (Turing award)
10/1/03 07:21 CS345 - Programming Languages 3
Historical Origins
n Foundations of Mathematics (1879-1936)n Paradoxes of set theory
n Cantor, Frege, Russell’s paradoxn Axiomatic systems, mathematical logic & type theory
n Hilbert, Bernays, Brouwer, Russell, Tarski, Zermelo, Fraenkel, …n Gödel’s Incompleteness Theoremn Metamathematics => a theory of computable functions
n combinators, “currying” – Moses Schönfinkel (1924)n combinatory logic - Haskell Curry (1930)n l-calculus – Alonzo Church (1934)n m-recursive functions – Stephen Kleene (1936)n turing machines – Alan Turing (1936)n others: Herbrand, Kolmogorov, Post, …
10/1/03 07:21 CS345 - Programming Languages 4
Alonzo Church
n PhD from Princeton University, 1927n Advisor was Oswald Veblen (who advised R.L. Moore of UT)n Studied with David Hilbert, Paul Bernays & L.E.J. Brouwer in Germanyn PhD students are “founding fathers” of theoretical computer science
n Stephen Kleene, 1934 (recursive function theory)n J. Barkley Rosser, 1934 (logic, Church-Rosser theorem)n Alan Turing, 1938 (computational logic & computability)n Leon Henkin, 1947 (logic, completeness proofs)n Martin Davis, 1950 (logic, computability theory)n J. Hartley Rogers, 1952 (recursive function theory)n Michael Rabin, 1956 (probabilistic algorithms – Turing award)n Dana Scott, 1958 (prob. algorithms, domain theory – Turing award)n Raymond Smullyan, 1959 (logic, tableau method, formal systems)n Simon Kochen, 1959 (Kochen-Specker theorem in QM)n Peter B. Andrews, 1964 (logic, type theory)
10/1/03 07:21 CS345 - Programming Languages 5
Computers and Programming
“The computer and programming languages were invented by logicians asthe unexpected by-product of their unsuccessful effort to formalize[mathematical] reasoning completely. Formalism failed for reasoning, butit succeeded brilliantly for computation. In practice, programmingrequires more precision than proving theorems!”
- Gregory J. Chaitin, co-founder of Algorithmic Information Theory
Quoted from: A Hundred Years of Controversy Regarding theFoundations of Mathematics, in the The Unknowable, Springer-Verlag,1999.
10/1/03 07:21 CS345 - Programming Languages 6
Computation and Information
n What constitutes a computation?n a mechanical rearrangement of symbols
n based on well-defined syntactic transformation rules (a calculus)n what do the symbols mean and what is a meaningful
computation? what is information anyway?n how do humans (or machines) interpret the result constructively
n A simple but powerful answern symbolic term rewriting
n substitution of terms according to well-defined rulesn reduction of resulting intermediate expressions to a normal formn the result is called a computation
10/1/03 07:21 CS345 - Programming Languages 7
A computational point of view
n a function in set theory is a graphn characterized solely by an input->output relation
n extensional equality - two functions f,g are equal iff they have thesame graph, i.e., {(x,y) | y = f(x) = g(x) }
n this doesn’t work too well in programming!n in what way are two sorting functions equivalent?
n intensional equality – equivalent algorithmic complexity
n how the function computes its result is importantn in CS we characterize a function by its algorithm:
n E.g., a O(n2) vs O(n log2 n) sorting algorithm
10/1/03 07:21 CS345 - Programming Languages 8
Some functional notations
Set Theoretic:
{(x,y) | Vx,y e NN: y = x2}
Algebraic:f: NN->NNf(x) = x2;
Type-free l-notation:
lx.x * x
Typed l-notation:
lx:int.x * x
Polymorphic l-notation:
lx:a.x * x
Scheme:(define square (lambda (x) (* x x)))
Algol:integer procedure square(x); integer x;begin square := x * x end;
Pascal:function square (x:integer) : integer;begin square := x * x end;
K&R C:square(x) int x; { return (x * x); }
StdC/C++/Java:int square(int x) { return (x * x); }
ML97:fun square x = x * x;fun square (x:int) = x * x;val square = fn x => x * x;
Haskell:square :: Int->Intsquare x = x * xmap (\x -> x * x) [0..][(x,y) | x <- [0..], y <- [x * x]]
10/1/03 07:21 CS345 - Programming Languages 9
Definitions
n l-calculus is a formal notation for defining functionsn expressions in this notation are called l-expressionsn every l-expression denotes a function that is “out there”n a l-expression consists of 3 kinds of terms:
n variables: x,y,z, etc.n we use V, V1, V2, etc., for arbitrary variables
n abstractions: lV.En Where V is some variable and E is another l-term
n applications: (E1 E2)n Where E1 and E2 are l-terms
n applications are sometimes called combinations
10/1/03 07:21 CS345 - Programming Languages 10
Formal Syntax in BNF
<l-term> ::= <variable>| l <variable> . <l-term>| (<l-term> <l-term>)
<variable> ::= x | y | z | …
Or, more compactly:
E ::= V | lV.E | (E1 E2)
V :: = x | y | z | …
Where V is an arbitrary variable and Ei is an arbitrary l-expression.
We call lV the head of the l-expression and E the body.
10/1/03 07:21 CS345 - Programming Languages 11
Variables
n variables can be bound or freen the l-calculus assumes an infinite universe of free variablesn they are bound to functions in an environmentn they become bound by usage in an abstraction
n for example, in the l-expression: lx.x*y
x is bound by l over the body x * y, but y is a free variable. I.e.,lexically scoped. Compare this to scheme:
(define z 3)(define x 2)(define y 2)(define multi-by-y (lambda (x) (* x y)))(multi-by-y z) => 6
10/1/03 07:21 CS345 - Programming Languages 12
Abstractions
n if lV.E is an abstractionn V is a bound variable over the body En it denotes the function that when given an actual argument ‘a’,
evaluates to the function E’ with all occurrences of V in E replacedwith ‘a’, written E[a/V]
n For example the abstraction: lx.x
is the identity function (lx.x)1 => 1 (lx.x)a => a
(lx.x)(lx.x) => (lx.x)
10/1/03 07:21 CS345 - Programming Languages 13
Applications
n If E1 and E2 are l-expressions, so is (E1 E2)n application is basically function evaluationn apply the function E1 to the argument E2
n E1 is called the rator (ope-rator)n E2 is called the rand (ope-rand)
n For example:(lx.xx) 1 => 11(lx.xx) a => aa
(lx.xx)(lx.xx) => (lx.xx)(lx.xx)
this last example is a quine, and it doesn’t terminate! It keepsduplicating itself ad infinitum. In this example, we don’t care, but inreal programming we do care about non-terminating evaluations!
10/1/03 07:21 CS345 - Programming Languages 14
Conversion/reduction rules
n a-conversionAny abstraction lV.E can be converted to
lV.E[V’/V] iff [V’/V] in E is valid
n b-conversion (b-reduction)Any application (lV.E1) E2 can be converted toE1[E2/V] iff [E2/V] in E1 is valid
n h-conversionAny abstraction lV.(E V) where V has no freeoccurrences in E can be converted to E
10/1/03 07:21 CS345 - Programming Languages 15
Conversion rule notation
aE1 E2
E1 E2b
E1 E2
h
bound variable renaming to avoidnaming conflicts
like a function call evaluation
elimination of irrelevant information
10/1/03 07:21 CS345 - Programming Languages 16
a-redex
aE1 E2
a-reduction is bound variable renamingapplied to an a-redex iff no namingconflicts
redex = reducible expression
lx.xa
ly.y
lx.f xa
ly.f y
(lx.x)[y/x]
(lx.f x)[y/x]
lx.ly.x+ya
ly.ly.f y+y not valid since y is alreadya bound variable in E1
10/1/03 07:21 CS345 - Programming Languages 17
b-redex
E1 E2b
(lx.f x) E bf E
(lx.(ly. x + y)) 3b
ly.3 + y
(ly.3 + y) 4b
3 + 4
10/1/03 07:21 CS345 - Programming Languages 18
Is the l-calculus Turing complete?
n Can we represent the class of Turing computable functions?n yes, we can represent
n Booleans and conditional functionsn numerals and arithmetic functionsn data structures, such as ordered pairs, lists, etc.n recursion
n doing so however is syntactically tedious!n actual programming languages use syntactic sugar for functions
n lambda expressions exist in Scheme, ML, Haskell, and even Pythonn l-calculus is more suitable as an abstract model of a programming
language rather than as a practical programming languagen it is used to study programming languages semantics from a mathematical
perspective called Denotational Semanticsn see the appendix in the Revised Report(5) on the Algorithmic Language Scheme
on course website for the denotational semantics of Scheme
10/1/03 07:21 CS345 - Programming Languages 19
Example of Syntactic Sugar in Scheme
As we have seen, Scheme has let and let* operators for establishinglocal bindings of variables to values over a lexically scoped block. In alet expression, all values in the list of let bindings are evaluated, andthen bound to the local variables. In a let* expression, the values areevaluated and bound to the variables sequentially:(define x 2)
(let ((x 3)(y x)) (* x y)) => 6(let*((x 3)(y x)) (* x y)) => 9
Which are just syntactic sugar for:
((lambda (x y) (* x y)) 3 x) => 6((lambda (x) ((lambda (y) (* x y)) x)) 3) => 9
10/1/03 07:21 CS345 - Programming Languages 20
Church Booleans
n We define booleans and logical operators in the l-calculus as functions:
True = T = lt.lf.t = ltf.t False = F = lt.lf.f = ltf.f AND = lxy.xy(ltf.f) = lxy.xyF
OR = lxy.x(ltf.t)y = lxy.xTyNEG = lx.x(luv.v)(lab.a) = lx.xTF
n Example:NEG True = (lx.x(luv.v)(lab.a))(ltf.t)
=> (ltf.t)(luv.v)(lab.a) => (luv.v) => False
10/1/03 07:21 CS345 - Programming Languages 21
Church Booleans
n We define true and false in the l-calculus asfunctions:
true = lt.lf.t
false = lt.lf.f
We can then define a conditional test function: test = lc.lx.ly.c x y
where test true v w = (lc.lx.ly.c x y) true v w
=>* true v w
= (lt.lf.t) v w
=>* v
10/1/03 07:21 CS345 - Programming Languages 22
Church Numerals
n The natural numbers may be defined using zero andthe successor function:n 0, 1=succ(0), 2=succ(succ(0)), …, etc.
n In the l-calculus, we only have functions, so we definethe natural numbers as functions:n 0 = ls.(lz.z), but we will write this as lsz.z,n then the rest of the natural numbers can be defined as:
n 1 = lsz.s(z), 2= lsz.s(s(z)), 3= lsz.s(s(s(z))), …, etc.
10/1/03 07:21 CS345 - Programming Languages 23
Successor function
n So how do we write a successor function?n S = lwyx.y(wyx)n Let’s test it on zero = lsz.z
n S0 = (lwyx.y(wyx))(lsz.z)=> lyx.y((lsz.z)yx) => lyx.y((lz.z)x)=> lyx.y(x)= 1
n Note that lyx.y(x) = lsz.s(z) under a-conversionn the variables names are “dummy variables”
10/1/03 07:21 CS345 - Programming Languages 24
Curried Functions
n Named after Haskell Curry who used them incombinatory logicn but first used by Moses Schonfinkel in the 1920s
n The basic idea is that any n-ary function can bereplaced by a composition of n unary functions.n f(x,y) => (fx)y
n f(x1,x2,…xn) => ((..((fx1)x2)..)xn)
10/1/03 07:21 CS345 - Programming Languages 25
Curried Function in Scheme
n Non-curried sumn (define sum (lambda (x y) (+ x y)))
n (sum 2 3) => 5
n Curried sumn (define sum (lambda (x) (lambda (y) (+ x y))))
n ((sum 2) 3) => 5
n (let ((f (sum 2))) (f 3)) => 5
10/1/03 07:21 CS345 - Programming Languages 26
Lambda and curried functions in MLn A lambda in ML is written as “fn <args> => <body>”
n val sum = fn x => fn y => x + y;
n val it = fn : int -> int -> int
n sum 3 2;
n val it = 5 : int
n A curried versionn fun sum x = fn y => x + y;
n val sum = fn : int -> int -> int
n sum 3;
n val it = fn : int -> int
n it 2;
n val it = 5 : int
n (sum 3) 2;
n val it = 5 : int
n sum 3 2;
n val it = 5 : int
10/1/03 07:21 CS345 - Programming Languages 27
Lambda expressions in Haskell
n Lambdas are written using “\<arg> -> <body>”n succ = \n -> n + 1
n succ 0 => (\n -> n + 1) 0 => 0 + 1 => 1n succ = (\a -> \b -> a + b) 1
n succ 0 => ((\a -> \b -> a + b) 1) 0=> (\b -> 1 + b) 0=> 1 + 0=> 1
n Note the syntactic similarity to the lambda-calculusn but we usually prefer the syntactic sugar form
n succ n = n + 1n succ 0 => 0 + 1 => 1n succ (succ 0) => succ (0+1) => succ 1 => 1+1 => 2
10/1/03 07:21 CS345 - Programming Languages 28
Comparing map & fold using lambda
n Map and foldl are similar across functional languagesn but note the order of the “don’t care” argument in the fold examplesn Scheme (using DrScheme)
n (map (lambda (x) (* x x)) ‘(1 2 3 4 5))) => (1 4 9 16 25)n (foldl (lambda (_ x) (+ 1 x)) 0 ‘(1 2 3 4 5)) => 5
n ML (using SML)n map (fn x => x * x) [1,2,3,4,5]; => [1,4,9,16,25]:int list
n foldl (fn (_,x) => x + 1) 0 [1,2,3,4,5]; => 5 : int
n Haskell (using Hugs)n map (\x -> x * x) [1,2,3,4,5] => [1,4,9,16,25]n foldl (\x _ -> x + 1) 0 [1,2,3,4,5] => 5n foldl (\x _ -> x + 1) 0 “Hello, world” => 12
n note: strings literals in Haskell are just arrays of characters
10/1/03 07:21 CS345 - Programming Languages 29
Homework
n Show the following in the l-calculus:n AND True True => True
n AND True False => False
n OR True False => True
n OR False False => False
10/1/03 07:21 CS345 - Programming Languages 30
Homework
n Show how to express the following in the l-calculus:n S1, S2, S3
n Addition in the l-calculusn let 2S3 represent 2+3n write the l-expression for 2S3
n note that you will have to use a-conversion to avoid name conflictn show that 2S3 reduces to SS3n show that SS3 reduces to S4n show that S4 equals (under a-conversion) the l-expression for 5
n Multiplication is done using the expression: lxyz.x(yz)n show that 2*2 or (lxyz.x(yz)) 2 2 => lsz.s(s(s(s(z)))) = 4 under a-
conversion