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

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

Concepts of programming languages

Graphical Untyped Lambda Calculus Interactive Interpreter

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

Type Systems Winter Semester 2006

Introduction to the λ-calculus

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

Chapter 5: The Untyped Lambda Calculus

Lambda Calculus. CS 550 Programming Languages Jeremy Johnson

Untyped Lambda Calculus

dynamically typed dynamically scoped

CIS 500 Software Foundations Fall September 25

Untyped Lambda Calculus

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

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

Lesson 4 Typed Arithmetic Typed Lambda Calculus

Lambda Calculus.

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

CSE-321 Programming Languages 2010 Midterm

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

Lambda Calculus. Concepts in Programming Languages Recitation 6:

Trees. Solution: type TreeF a t = BinF t a t LeafF 1 point for the right kind; 1 point per constructor.

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

Programming Languages Fall 2014

Type families and data kinds

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

Lecture 5: The Untyped λ-calculus

The Untyped Lambda Calculus

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

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

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

CMSC 330: Organization of Programming Languages. Lambda Calculus Encodings

Getting Started with Haskell (10 points)

Chapter 5: The Untyped Lambda Calculus

CMSC 330: Organization of Programming Languages

Exercise 1 ( = 22 points)

CMSC 330: Organization of Programming Languages

5. Introduction to the Lambda Calculus. Oscar Nierstrasz

The Untyped Lambda Calculus

Exercise 1 ( = 18 points)

Testing. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 2. [Faculty of Science Information and Computing Sciences]

GADTs. Alejandro Serrano. AFP Summer School. [Faculty of Science Information and Computing Sciences]

More Untyped Lambda Calculus & Simply Typed Lambda Calculus

T ::=Nat T T. zero : Nat. This rule can be instantiated for any type T, so it is actually a family of rules, one for each type.

Exercise 1 ( = 24 points)

CSC312 Principles of Programming Languages : Functional Programming Language. Copyright 2006 The McGraw-Hill Companies, Inc.

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

1.3. Conditional expressions To express case distinctions like

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

Getting Started with Haskell (10 points)

Fall 2013 Midterm Exam 10/22/13. This is a closed-book, closed-notes exam. Problem Points Score. Various definitions are provided in the exam.

Formal Semantics. Aspects to formalize. Lambda calculus. Approach

Lambda Calculus and Type Inference

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

CIS 500 Software Foundations Midterm I

Pure Lambda Calculus. Lecture 17

CSE-321 Programming Languages 2012 Midterm

CS 11 Haskell track: lecture 1

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

Denotational Semantics. Domain Theory

Programming Languages Lecture 14: Sum, Product, Recursive Types

CMSC 330: Organization of Programming Languages. Lambda Calculus

Formal Systems and their Applications

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

Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy

Simon Peyton Jones Microsoft Research. August 2012

1 Scope, Bound and Free Occurrences, Closed Terms

CIS 500 Software Foundations Fall October 2

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

CMSC330. Objects, Functional Programming, and lambda calculus

Lecture Notes on Data Representation

Typed Scheme: Scheme with Static Types

CS 11 Haskell track: lecture 5. This week: State monads

Lambda Calculus and Type Inference

Programming Languages Fall 2013

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

LECTURE 16. Functional Programming

Simple Unification-based Type Inference for GADTs

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

COMP 4161 NICTA Advanced Course. Advanced Topics in Software Verification. Toby Murray, June Andronick, Gerwin Klein

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

CSE 505: Concepts of Programming Languages

Programming Language Concepts: Lecture 14

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

Functional Programming

Shell CSCE 314 TAMU. Haskell Functions

Parsing. Zhenjiang Hu. May 31, June 7, June 14, All Right Reserved. National Institute of Informatics

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.

CS 440: Programming Languages and Translators, Spring 2019 Mon

CSCE 314 TAMU Fall CSCE 314: Programming Languages Dr. Flemming Andersen. Haskell Functions

Recursion. Lecture 6: More Lambda Calculus Programming. Fixed Points. Recursion

CMSC 330: Organization of Programming Languages

Lambda Calculus. Gunnar Gotshalks LC-1

Lambda Calculus. Variables and Functions. cs3723 1

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

Lambda Calculus LC-1

CMSC 330: Organization of Programming Languages. Lambda Calculus

Transcription:

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

Today Lambda calculus the foundation of functional programming What makes lambda calculus such a universal language of computation? 2

The Lambda Calculus Introduced by Church 1936 (or even earlier). Formal language based on variables, function abstraction and application (substitution). Allows to express higher-order functions naturally. Equivalent in computational power to a Turing machine. Is at the basis of functional programming languages such as Haskell. 3

What and why? A simple language with relatively few concepts. Easy to reason about. Original goal: reason about expressiveness of computations. Today more: core language for playing with all sorts of language features. Many flavours: untyped, typed, added constants and constructs. 4

Lambda calculus: definition There are only three constructs: e ::= x (variables) e e (application) λ x -> e (abstraction) 5

Conventions Note: application associates to the left: a b c = (a b) c Note: only unary functions and unary application but we write λ x y -> e for λ x -> (λ y -> e). Note: the function body of a lambda extends as far as possible to the right: λ x -> e f should be read as λ x -> (e f) 6

Definitions We usually consider terms equal up to renaming (alpha equivalence); The central computation rule is beta reduction: (λ x -> e) (a) reduces to e [x/a] 7

Applications? It seems as if we can do nothing useful with the lambda calculus. There are no constants no numbers, for instance. But it turns out that we can encode recursion, numbers, booleans, and just about any other data type. 8

Church numerals zero = λ s z -> z one = λ s z -> (s z) two = λ s z -> (s (s z)) three = λ s z -> (s (s (s z)))... So far, so good, but can we calculate with these numbers? 9

Addition suc = λ n -> λ s z -> (s (n s z))) add = λ m n -> m suc n Does this work as expected? 10

Addition suc = λ n -> λ s z -> (s (n s z))) add = λ m n -> m suc n Does this work as expected? suc two 10

Addition suc = λ n -> λ s z -> (s (n s z))) add = λ m n -> m suc n Does this work as expected? suc two (λ n -> (λ s z -> (s (n s z)))) two 10

Addition suc = λ n -> λ s z -> (s (n s z))) add = λ m n -> m suc n Does this work as expected? suc two (λ n -> (λ s z -> (s (n s z)))) two λ s z -> (s (two s z)) 10

Addition suc = λ n -> λ s z -> (s (n s z))) add = λ m n -> m suc n Does this work as expected? suc two (λ n -> (λ s z -> (s (n s z)))) two λ s z -> (s (two s z)) λ s z -> (s (s (s z))) 10

Church Booleans true = λ t f -> t false = λ t f -> f ifthenelse = λ c t e -> c t e 11

Church Booleans true = λ t f -> t false = λ t f -> f ifthenelse = λ c t e -> c t e The function ifthenelse is almost the identity function. and = λ x y -> ifthenelse x y false and = λ x y -> x y false or = λ x y -> ifthenelse x true y or = λ x y -> x true y 11

Church Booleans true = λ t f -> t false = λ t f -> f ifthenelse = λ c t e -> c t e The function ifthenelse is almost the identity function. and = λ x y -> ifthenelse x y false and = λ x y -> x y false or = λ x y -> ifthenelse x true y or = λ x y -> x true y The function iszero takes a number and returns a Bool. iszero = λ n -> (n (λ x -> false) true) 11

Pairs pair = λ x y -> (λ p -> (p x y)) fst = λ p -> (p (λ x y -> x)) snd = λ p -> (p (λ x y -> y)) The function pair remembers its two parameters and returns them when asked by its third parameter. 12

How do you come up with these definitions? 13

Church encoding for arbitrary datatypes There is a correspondence between the so-called fold (or catamorphism or eliminator) for a datatype and its Church encoding. Haskell: data Nat = Suc Nat Zero foldnat Zero s z = z foldnat (Suc n) s z = s (foldnat n s z) Lambda calculus: zero = λ s z -> z suc n = λ s z -> (s (n s z)) 14

Church encoding for arbitrary datatypes contd. Haskell: data Bool = True False foldbool True t f = t foldbool False t f = f Lambda calculus: true = λ t f -> t false = λ t f -> f Note that foldbool is just ifthenelse again. 15

Church encoding for arbitrary datatypes contd. Haskell: data Pair x y = Pair x y foldpair (Pair x y) p = p x y Lambda calculus: pair = λ x y -> (λ p -> (p x y)) 16

Encoding vs. adding constants The fact that we can encode certain entities in the lambda justifies that we can add them as constants to the language without changing the nature of the language. 17

Example (adding Booleans) e ::= true false if e then e else e Once we have new forms of expressions, we need more than just beta-reduction: if true then e1 else e2 --> e1 if false then e1 else e2 --> e2 18

Towards Haskell Haskell is based on the lambda calculus. Yet, so far it seems hard to believe that we can desugar Haskell to some form of lambda calculus. 19

Binding names with let Haskell allows us to bind identifiers to expressions in the language using let. We have only introduced informal abbreviations for lambda terms so far such as true or iszero. 20

Binding names with let contd. In fact, let can simply be desugared to a lambda binding. let x = e1 in e2 = (λ x -> (e2)) e1 Note that this does not work if x is a recursive binding or if you want to preserve sharing. What about recursion, then? 21

Recursion Haskell example fac = \ n -> if n == 0 then 1 else n * fac (n - 1) fac = fix (\fac n -> if n == 0 then 1 else n * fac (n - 1)) The desired function fac can be viewed as a fixed point of the related non-recursive function fac. 22

Fixed points A fixed-point combinator is a combinator fix with the property that for any f, -- Using recursion directly fix f = f (fix f) In particular, fix fac' = fac' (fix fac') thus fix fac is a fixed point of fac. 23

Fixed-point combinators Many fixed-point combinators can be defined in the untyped lambda calculus. Here is one of the smallest and most famous ones, called Y. Y = λ f -> (λ x -> (f (x x))) (λ x -> (f (x x))) 24

Verification that Y is a fixed-point combinator Y f 25

Verification that Y is a fixed-point combinator Y f = (λ x -> (f (x x))) (λ x -> (f (x x))) 25

Verification that Y is a fixed-point combinator Y f = (λ x -> (f (x x))) (λ x -> (f (x x))) = f ((λ x -> (f (x x))) (λ x -> (f (x x)))).. = f (Y f) 25

Recap It is thus possible to desugar a recursive Haskell definition into the lambda calculus by translating recursion into applications of fix. Conversely, we can justify adding recursion as a construct to the lambda calculus without changing its essential nature. 26

General vs. structural recursion Note that most recursive functions can actually be defined without a fixed-point combinator. We have already defined add: add = λ m n -> (m suc n) In Haskell, add would be recursive data Nat = Suc Nat Zero add (Suc m) n = Suc (add m n) add Zero n = n but can also be defined in terms of foldnat: 27 add m n = foldnat m Suc n

General vs. structural recursion contd. Functions defined in terms of a fold function are called structurally recursive. Recursion using the fixed-point combinator is called general recursion. Writing functions using general recursion is often perceived as simpler or more direct. Structural recursion is often more well-behaved. For instance, for many datatypes it can be proved that if the arguments to the fold terminate, the structurally recursive function also terminates. 28

Pattern matching In Haskell we can define functions using pattern matching: data Nat = Suc Nat Zero pred (Suc m) pred Zero = m = Zero Question How can we define pred for the Church numerals? 29

Case function Alternatively, pattern matching via case on a natural number can be captured as a function: casenat :: Nat -> (Nat -> r) -> r -> r casenat (Suc n) s z = s n casenat Zero s z = z pred = \m -> casenat m (\ m' -> m') Zero The case function can be expressed in terms of the fold for that datatype, and hence the Church encoding. 30

Case function contd. Haskell: casenat :: Nat -> (Nat -> r) -> r -> r casenat (Suc n) s z = s n casenat Zero s z = z foldnat :: Nat -> (s -> s) -> s -> s foldnat (Suc n) s z = s (foldnat n s z) foldnat Zero s z = z 31

Case via fold We call foldnat choosing s = (r, Nat) that is pairing the return type and natural number: casenat n s z = fst (foldnat n (\(_,r) -> (s r, Suc r)) (z, zero)) The second component of the pair just constructs the natural number again. This is how we can access the predecessor! 32

Nested patterns Haskell allows nested patterns, too: fib Zero = Zero fib (Suc Zero) = Suc Zero fib (Suc (Suc n)) = add (fib n) (fib (Suc n)) These can easily be desugared to nested applications of case using only flat patterns (and hence to applications of casenat): fib n = case n of Zero Suc n' -> Zero -> case n' of... 33

Recap We have seen how most Haskell constructs can be desugared to the lambda calculus: constructors of datatypes using the Church encoding, non-recursive let using lambda abstractions, general recursion using a fixed-point combinator, pattern matching using possibly nested applications of case functions. 34

Recap contd. Many other Haskell constructs can be expressed in terms of the ones we have already seen for instance: where-clauses can be transformed into let if-then-else can be expressed as a function list comprehensions can be transformed into applications of map, concat and if-then-else monadic do notation can be transformed into applications of a limited number of functions 35

Even Simpler A straightforward implementation of the lambda calculus may give rise to abitrary large reduction steps. We can represent all lambda expressions using only three combinators with the following reduction behaviour: S f g x = (f x) (g x) K y x = y I x = x 36

Translation Given a lambda term of the form how can we translate this to an expression using SKI? data SKI = Var String S K I App SKI SKI toski :: Lambda -> SKI toski (Var x) = Var x toski (App t1 t2) = (toski t1) `App`(toSKI t2) toski (Lam x t) = remove x (toski t) The auxiliary function remove does the actual work 37

Bracket abstraction remove :: Var -> SKI -> SKI remove x (Var y) x == y = I remove x (App t1 t2) = S `App` (remove x t1) `App` (remove x t2) remove x s = K `App` s This is sometimes called bracket abstraction. 38

Intuition What s going on? S f g x = (f x) (g x) K y x = y I x = x S is duplicating a variable; K is discarding a variable; I is using a variable. 39

Intuition What s going on? S f g x = (f x) (g x) K y x = y I x = x S is duplicating a variable; K is discarding a variable; I is using a variable. Bracket abstraction simply explains how to route the argument of a function to the variable s occurrences in the lambda s body. 39

Alternatives Haskell Curry proposed the following combinators: B x y z = x (y z) C x y z = x z y K x y = x W x y = x y y Here B routes arguments to the left only; C routes arguments to the right; and W duplicates its inputs. 40

Even Simpler The combinator I is superfluous: S K K x --> (K x) (K x) --> x and hence I = S K K 41

Even Simpler In 1989 Jeroen Fokker (UU) invented: X = λ f -> (f S f3) f3 = λ p -> p -- first of three with which we can define K as follows: K y x --> X X y x Does it reduce as expected? 42

Even Simpler In 1989 Jeroen Fokker (UU) invented: X = λ f -> (f S f3) f3 = λ p -> p -- first of three with which we can define K as follows: K y x --> X X y x Does it reduce as expected? 42 --> X S f3 y x --> S S f3 f3 y x --> S f3 (f3 f3) y x --> f3 y (f3 f3 y) x --> y

Even simpler Check for yourself: S = X (X X) 43

Back to Haskell This is nice but what does this have to do with Haskell? 44

Back to Haskell This is nice but what does this have to do with Haskell? GHC translates to an intermediate language: GHC Core. GHC Core is really little more than a (typed) lambda calculus. You can read the spec on GitHub. 44

Core sketch GHC Core is based on System Fc a typed lambda calculus extended with type coercions. variables, lambdas, and application; literals; let bindings; case expressions; coercions used to implement GADTs and type families; ticks used for HPC to track program coverage. Inspecting core can be useful to see how code is generated and optimized. 45

Generating core alias ghci-core="ghci -ddump-simpl \ -dsuppress-idinfo -dsuppress-coercions \ -dsuppress-type-applications \ -dsuppress-uniques -dsuppress-module-prefixes" The following Haskell code and corresponding Core: f :: Int -> Int f x = x + 1 f :: Int -> Int f = \ (x :: Int) -> case x of _ { I# x1 -> I# (+# x1 1) } 46

What we haven t discussed yet Types Compare false = λ t f -> f zero = λ s z -> z We can easily write terms that do not make sense in lambda calculus; Haskell has types to prevent that. Overloading In Haskell, functions can be overloaded using type classes. How can such overloading be resolved and desugared? 47

What we haven t discussed yet contd. Laziness Haskell makes use of a particular evaluation strategy called lazy evaluation. We have not looked at evaluation strategies at all so far. Side effects The lambda calculus has no notion of effects, not even encapsulated effects such as Haskell offers with IO. So the behaviour of IO cannot be described by reduction to the lambda calculus. 48

Conclusion The lambda calculus has many applications. 49