Introduction to the λ-calculus

Similar documents
COMP 1130 Lambda Calculus. based on slides by Jeff Foster, U Maryland

λ-calculus Lecture 1 Venanzio Capretta MGS Nottingham

Lecture 5: The Untyped λ-calculus

CMSC 330: Organization of Programming Languages

Programming Language Features. CMSC 330: Organization of Programming Languages. Turing Completeness. Turing Machine.

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages

Pure (Untyped) λ-calculus. Andrey Kruglyak, 2010

CMSC 330: Organization of Programming Languages. Lambda Calculus Encodings

Formal Semantics. Aspects to formalize. Lambda calculus. Approach

CMSC 330: Organization of Programming Languages

INF 212 ANALYSIS OF PROG. LANGS LAMBDA CALCULUS. Instructors: Crista Lopes Copyright Instructors.

CMSC330. Objects, Functional Programming, and lambda calculus

Lambda Calculus. CS 550 Programming Languages Jeremy Johnson

5. Introduction to the Lambda Calculus. Oscar Nierstrasz

Type Systems Winter Semester 2006

CMSC 330: Organization of Programming Languages. Lambda Calculus

Lambda Calculus alpha-renaming, beta reduction, applicative and normal evaluation orders, Church-Rosser theorem, combinators

3.1 λ-calculus: Syntax

VU Semantik von Programmiersprachen

λ calculus Function application Untyped λ-calculus - Basic Idea Terms, Variables, Syntax β reduction Advanced Formal Methods

Activity. CSCI 334: Principles of Programming Languages. Lecture 4: Fundamentals II. What is computable? What is computable?

The Untyped Lambda Calculus

Untyped Lambda Calculus

dynamically typed dynamically scoped

CIS 500 Software Foundations Fall September 25

11/6/17. Outline. FP Foundations, Scheme. Imperative Languages. Functional Programming. Mathematical Foundations. Mathematical Foundations

Introduction to the Lambda Calculus

Introduction to Lambda Calculus. Lecture 7 CS /08/09

Introduction to Lambda Calculus. Lecture 5 CS 565 1/24/08

CMSC 330: Organization of Programming Languages

Lambda Calculus and Extensions as Foundation of Functional Programming

CMSC 330: Organization of Programming Languages. Lambda Calculus

Functions as data. Massimo Merro. 9 November Massimo Merro The Lambda language 1 / 21

The Lambda Calculus. 27 September. Fall Software Foundations CIS 500. The lambda-calculus. Announcements

9/23/2014. Why study? Lambda calculus. Church Rosser theorem Completeness of Lambda Calculus: Turing Complete

Lambda Calculus. Type Systems, Lectures 3. Jevgeni Kabanov Tartu,

One of a number of approaches to a mathematical challenge at the time (1930): Constructibility

CSE 505: Concepts of Programming Languages

Untyped Lambda Calculus

Chapter 11 :: Functional Languages

A Quick Overview. CAS 701 Class Presentation 18 November Department of Computing & Software McMaster University. Church s Lambda Calculus

1 Scope, Bound and Free Occurrences, Closed Terms

Lambda Calculus. Lecture 4 CS /26/10

Introduction to the Lambda Calculus. Chris Lomont

n λxy.x n y, [inc] [add] [mul] [exp] λn.λxy.x(nxy) λmn.m[inc]0 λmn.m([add]n)0 λmn.n([mul]m)1

Functional Programming

Fundamentals and lambda calculus

Elixir, functional programming and the Lambda calculus.

The Untyped Lambda Calculus

Constraint-based Analysis. Harry Xu CS 253/INF 212 Spring 2013

Programming Languages

Fundamentals and lambda calculus. Deian Stefan (adopted from my & Edward Yang s CSE242 slides)

CS 4110 Programming Languages & Logics. Lecture 17 Programming in the λ-calculus

Whereweare. CS-XXX: Graduate Programming Languages. Lecture 7 Lambda Calculus. Adding data structures. Data + Code. What about functions

CITS3211 FUNCTIONAL PROGRAMMING

CMSC 336: Type Systems for Programming Languages Lecture 4: Programming in the Lambda Calculus Acar & Ahmed 22 January 2008.

Last class. CS Principles of Programming Languages. Introduction. Outline

Introductory Example

Lambda Calculus and Type Inference

4/19/2018. Chapter 11 :: Functional Languages

M. Snyder, George Mason University LAMBDA CALCULUS. (untyped)

Computer Science 203 Programming Languages Fall Lecture 10. Bindings, Procedures, Functions, Functional Programming, and the Lambda Calculus

Concepts of programming languages

CS152: Programming Languages. Lecture 7 Lambda Calculus. Dan Grossman Spring 2011

CS 6110 S14 Lecture 1 Introduction 24 January 2014

Lambda Calculus. Lambda Calculus

Lambda calculus. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 6

10.6 Theoretical Foundations

The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS

Chapter 5: The Untyped Lambda Calculus

Graphical Untyped Lambda Calculus Interactive Interpreter

Pure Lambda Calculus. Lecture 17

Lambda Calculus as a Programming Language

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages. Lambda calculus

Recursive Definitions, Fixed Points and the Combinator

CITS3211 FUNCTIONAL PROGRAMMING. 10. Programming in the pure λ calculus

Lambda Calculus. Variables and Functions. cs3723 1

Lexicografie computationala Feb., 2012

Lecture #3: Lambda Calculus. Last modified: Sat Mar 25 04:05: CS198: Extra Lecture #3 1

Formal Systems and their Applications

More Lambda Calculus and Intro to Type Systems

Lecture 9: More Lambda Calculus / Types

- M ::= v (M M) λv. M - Impure versions add constants, but not necessary! - Turing-complete. - true = λ u. λ v. u. - false = λ u. λ v.

Programming Language Pragmatics

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Chapter 2 The Language PCF

Part I. Historical Origins

Lambda Calculus. Adrian Groza. Department of Computer Science Technical University of Cluj-Napoca

CIS 500 Software Foundations Fall October 2

Functional Languages. Hwansoo Han

From the λ-calculus to Functional Programming Drew McDermott Posted

Chapter 5: The Untyped Lambda Calculus

Functional Programming and λ Calculus. Amey Karkare Dept of CSE, IIT Kanpur

The Untyped Lambda Calculus

Denotational Semantics. Domain Theory

Lambda Calculus. Concepts in Programming Languages Recitation 6:

lambda calculus History 11/28/13 Jianguo Lu A formal system designed to inves:gate func:on defini:on, func:on applica:on, and recursion.

An Introduction to the Lambda Calculus

Lambda Calculus-2. Church Rosser Property

Transcription:

Announcements Prelim #2 issues: o Problem 5 grading guide out shortly o Problem 3 (hashing) issues Will be on final! Friday RDZ office hours are 11-12 not 1:30-2:30 1

Introduction to the λ-calculus Today we will take a look at the theoretical roots of functional programming in the form of a mathematical precursor to OCaml, the λ- (lambda-) calculus. The λ-calculus was invented by Alonzo Church in the 1930s to study the interaction of functional abstraction and function application from an abstract, purely mathematical point of view. It was one of many related systems that were proposed in the late 1920s and 1930s. o This was an exciting time for theoretical computer science, even though computers had not yet been invented. o There were many great mathematicians such as Alonzo Church, Kurt Gödel, Alan Turing, and Emil Post who were trying to understand the notion of computation. They certainly understood intuitively what an algorithm was, but they were lacking a formal mathematical definition. They came up with a number of different systems for capturing the general idea of computation: o Turing machines Alan Turing o μ-recursive functions Kurt Gödel o rewrite systems Emil Post o the λ-calculus Alonzo Church o combinatory logic Haskell Curry These systems all looked very different, but what was amazing was that they all turned out to be computationally equivalent in the sense that each could encode and simulate the others. 2

Church thought that this was too striking to be mere coincidence, and declared that they had found the correct definition of the notion of computability: it was the common spirit embodied in a different way by each one of these formalisms. o This declaration became known as Church's thesis. Nowadays we have a better understanding of computability, and one could add any modern general-purpose programming language such as Java, C, Scheme, or OCaml (suitably abstracted) to this list, but Church and his colleagues did not have that luxury. The λ-calculus The λ-calculus is like OCaml, except much simpler: o Everything is a function. There are no other types no integers, strings, lists, booleans, etc. There is no unit (). If you want these things, you must encode them using functions. Luckily, functions are powerful enough to do this. o There are no notions of state or side effects. It is purely functional. Thus we can think exclusively in terms of the substitution model. o The order of evaluation is irrelevant. OCaml imposes a certain evaluation order, namely eager evaluation evaluate the arguments before applying the function. The λ-calculus does not specify an evaluation order. o All functions are unary (take one argument). Functions of multiple arguments are encoded by currying. 3

Syntax λ-terms E,F,G,... are defined inductively: 1. variables: any variable x,y,z,... is a λ-term. 2. application: if E and F are λ-terms, then EF is a λ-term. 3. abstraction: if E is a λ-term and x is a variable, then λx.e is a λ-term. Notes: 1. This is the basis of the inductive definition of λ-terms. 2. The expression EF denotes application of E (considered as a function) to F (considered as an input). Think of this as an expression with an invisible infix operator apply between the E and F, like + or *. This might also be written (EF) or E(F) with parentheses as necessary to avoid ambiguity. The apply operator is not associative, so (EF)G is not the same as E(FG) in general. The expression EFG written without parentheses should be read as (EF)G. This is the same convention as in OCaml. 3. The expression λx.e would be written fun x -> E in OCaml. The application operator binds tighter than abstraction operator, so λx.λx.xy should be read as λx.(λx.(xy)). 4

Substitution Computation in the λ-calculus is effected by substitution. There are two rules: 1. α-conversion (renaming bound variables): λx.e => λy.(e{y/x}), where E{y/x} denotes the result of replacing all free occurrences of x in E by y, provided y would not be captured by a λy already in E. Examples: OK: λx.λy.xy => λz.λy.zy (rename x to z, nothing bad happened) not OK: λx.λy.xy => λy.λy.yy (rename x to y, y was captured) 2. β-reduction (substitution rule): (λx.e)f => E{F/x}, where E{F/x} denotes the result of replacing all free occurrences of x in E by F. Before doing this, bound variables in E are renamed by α-conversion if necessary to avoid capturing free variables in F. Examples: OK: (λx.λy.xy) (λz.z) => λy.(λz.z)y not OK: (λx.λy.xy) (λz.yz) => λy.(λz.yz)y (y was captured) but if we rename the bound y first, it's OK: (λx.λy.xy) (λz.yz) => (λx.λa.xa) (λz.yz) => λa.(λz.yz)a Examples in OCaml: 1. fun x -> x + 3 is equivalent to fun y -> y + 3. 2. This is just the substitution rule. (fun x -> x + 3) 7 => 7 + 3. An α- or β-reduction step can be performed at any time to any subterm of a λ- term. Write E => F if E goes to F in some finite number of α- or β-reduction steps. 5

Order of Evaluation In the λ-calculus, a reduction rule can be performed at any time to any subterm of a λ-term at which the rule is applicable. OCaml specifies an order of evaluation, but the λ-calculus does not. o It turns out that it does not matter because of the Church-Rosser theorem: If E => F 1 and E => F 2, then there always exists a G such that F 1 => G and F 2 => G. E / \ / \ / \ / \ F 1 F 2 G So if you diverge by applying rules to different parts of the term, you can always get back together again by applying more rules. Example: (fun x -> x + x) (2*3) / \ lazy/ \eager / \ / \ (2*3) + (2*3) (fun x -> x + x) 6 6 + 6 Terms are equivalent if they have a common reduct; that is, E 1 == E 2 if there exists an F such that E 1 => F and E 2 => F. E 1 E 2 F 6

The relation == is an equivalence relation on terms (reflexive, symmetric, transitive). To show transitivity, we use the Church-Rosser property: if E 1 == E 2 and E 2 == E 3, then there exist F 1 and F 2 such that E 1 E 2 E 3 F 1 F 2 By the Church-Rosser property, there exists a G such that F 1 => G and F 2 => G: E 1 E 2 E 3 F 1 F 2 G Thus E 1 => G and E 3 => G, which proves that E 1 == E 3. 7

Values A λ-term is said to be in normal form if there are no β-reductions that apply; that is, if there are no subterms of the form (λx.m)n. For example, the terms x and λx.y are in normal form. Terms in normal form correspond to values in OCaml. They are objects that cannot be evaluated further. A term is said to be normalizable if there is a sequence of α- and β- reductions that lead to a normal form. Because of the Church-Rosser property, if a term is normalizable, then its normal form is unique (up to α- conversion). A sequence of reductions leading to a normal form corresponds roughly to a halting computation in OCaml. Some terms are not normalizable. For example, (λx.xx)(λx.xx) is not. Even if a term is normalizable, there may be infinite reduction sequences that never lead to a normal form. For example, (λy.z)((λx.xx)(λx.xx)) reduces to the normal form z if it is evaluated lazily, but does not terminate if evaluated eagerly. 8

Encoding Other Data Types The λ-calculus is powerful enough to encode other data types and operations. Booleans Define true = λx.λy.x false = λx.λy.y In other words, true and false are curried two-argument functions that just return the first and second argument, respectively. We can then encode the conditional if-then-else as the identity function λx.x: if-then-else true B C => (λx.x) true B C => true B C => (λx.λy.x) B C => (λy.b) C => B if-then-else false B C => (λx.x) false B C => false B C => (λx.λy.y) B C => (λy.y) C => C We can define other Boolean operations: and = λx.λy.xyx or = λx.λy.xxy not = λx.(x false true) For example, and true false => (λx.λy.xyx) true false => true false true => (λx.λy.x) false true => false 9

Pairs and Tuples In OCaml, all the pairing operator (, ) does is package up two things in such a way that they can be extracted again by fst and snd. To code this in the λ-calculus, we can take two terms A and B and produce a function that will apply another function to them. Define pair = λx.λy.λc.cxy If we apply this to A and B we get pair A B = λc.(c A B) and this is how we encode the pair (A, B). Now we can extract A and B again by applying this function to true and false, respectively: (λc.(c A B)) true => true A B => (λx.λy.x) A B => A (λc.(c A B)) false => false A B => (λx.λy.y) A B => B so we should define fst = λd.(d true) snd = λd.(d false) 10

Lists We can encode lists as iterated tuples. Thus :: is the same as pair, hd is fst, and tl is snd. If we define the empty list [] appropriately, we can get a null test. Define [] = λx.true null = λd.(d λx.λy.false) Then null [] => λd.(d λx.λy.false) (λx.true) => (λx.true) (λx.λy.false) => true null (pair A B) => λd.(d λx.λy.false) (λc.(c A B)) => λc.(c A B) (λx.λy.false) => (λx.λy.false) A B => false 11

Numbers and Arithmetic In OCaml, numbers are a built-in primitive type. In the λ-calculus, we have to encode them as λ-terms. Church came up with a neat way to do this. His encoding is called the Church numerals. The idea is to encode the number n as a λ-term n representing a function that takes another function f as input and produces the n-fold composition of f with itself. 0 = λf.λx.x 1 = λf.λx.fx 2 = λf.λx.f(fx) 3 = λf.λx.f(f(fx))... n = λf.λx.f(...(f(f(fx)))...) Note that 0 is just false after α-conversion. Let's write f n x as an abbreviation for the term f(...(f(f(fx)))...) with n applications of f. Then n = λf.λx.f n x This is nice, but in order to do anything with it, we have to encode arithmetic. Let's start with the simplest operation, namely successor. We would like to define a λ-term add1 that when applied to any Church numeral n produces n+1. Note that nfx => f n x so f(nfx) => f(f n x) = f n+1 x λ-abstracting, we get λf.λx.f(nfx) => λf.λx.f n+1 x = n+1 Therefore we want our successor function to produce λf.λx.f(nfx) from n. Thus we just define add1 = λn.λf.λx.f(nfx) 12

How do we test for 0? iszero = λn.(n λz.false true) Then iszero 0 => λn.(n λz.false true) λf.λx.x => λf.λx.x λz.false true => true iszero n+1 => λn.(n λz.false true) λf.λx.f n+1 x => λf.λx.f n+1 x λz.false true => λx.(λz.false) n+1 x true => (λz.false) n+1 true => false Addition is just iterated successor. Note that m add1 => λf.λx.f m x add1 => λx.(add1 m x) thus m add1 n => λx.(add1 m x) n => add1 m n => m+n This suggests that we should define add = λn.λm.(m add1 n) Multiplication can be defined by iterated addition and exponentiation by iterated multiplication in a similar fashion. mul = λn.λm.(m (add n) 0) exp = λn.λm.(m (mul n) 1) Subtraction is more difficult, but it can be done. As above, we start by defining the predecessor function sub1, where sub1 n+1 = n sub1 0 = 0 Recall from our encoding of lists above that [] = λx.true [n; n-1; n-2;...; 2; 1; 0] = pair n [n-1; n-2;...; 2; 1; 0] so [...] represents a list in the usual OCaml sense under our encoding. Our approach is to come up with a term F such that 13

n F [0] => [n; n-1; n-2;...; 2; 1; 0] If we can concoct such a term F, then we can take sub1 = λn.(if-then-else (iszero n) 0 (fst (snd (n F [0])))) Note that n F [0] => F n [0] so this will work provided for all n we have F [n; n-1; n-2;...; 2; 1; 0] => [n+1; n; n-1; n-2;...; 2; 1; 0] This can be achieved by defining F = λx.(pair (add1 (fst x)) x) Proper subtraction (sub n m = 0 if n < m, n - m if n >= m) can be effected by iterating sub1 exactly as add was defined by iterating add1. 14