Week 4: Functional Programming

Similar documents
COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

Functional Programming

Programming Languages

Lambda Calculus. Variables and Functions. cs3723 1

Functional Languages. Hwansoo Han

Imperative languages

Functional Programming. Big Picture. Design of Programming Languages

LECTURE 16. Functional Programming

Functional Programming. Pure Functional Languages

Organization of Programming Languages CS3200/5200N. Lecture 11

Functional Programming. Pure Functional Languages

Functional Programming Languages (FPL)

Chapter 11 :: Functional Languages

CS 314 Principles of Programming Languages

FP Foundations, Scheme

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

The Untyped Lambda Calculus

Functional Programming. Pure Functional Programming

Fundamentals of Artificial Intelligence COMP221: Functional Programming in Scheme (and LISP)

CSCC24 Functional Programming Scheme Part 2

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

Recursive Definitions, Fixed Points and the Combinator

Principles of Programming Languages COMP251: Functional Programming in Scheme (and LISP)

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

CS 242. Fundamentals. Reading: See last slide

11/6/17. Functional programming. FP Foundations, Scheme (2) LISP Data Types. LISP Data Types. LISP Data Types. Scheme. LISP: John McCarthy 1958 MIT

Introduction to lambda calculus Part 3

CS 360 Programming Languages Interpreters

CPS 506 Comparative Programming Languages. Programming Language Paradigm

Chapter 15. Functional Programming Languages

The Untyped Lambda Calculus

Introduction to Scheme

Weeks 6&7: Procedures and Parameter Passing

CMSC330. Objects, Functional Programming, and lambda calculus

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

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

CS 314 Principles of Programming Languages

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Functional Programming and Haskell

CMSC 330: Organization of Programming Languages

Processadors de Llenguatge II. Functional Paradigm. Pratt A.7 Robert Harper s SML tutorial (Sec II)

Introduction to Functional Programming in Racket. CS 550 Programming Languages Jeremy Johnson

Programming Language Pragmatics

5. Introduction to the Lambda Calculus. Oscar Nierstrasz

COMP80 Lambda Calculus Programming Languages Slides Courtesy of Prof. Sam Guyer Tufts University Computer Science History Big ideas Examples:

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

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

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. Common Lisp Fundamentals

Foundations. Yu Zhang. Acknowledgement: modified from Stanford CS242

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

Chapter 1. Fundamentals of Higher Order Programming

Principles of Programming Languages 2017W, Functional Programming

Chapter 15. Functional Programming Languages

1.3. Conditional expressions To express case distinctions like

Denotational Semantics. Domain Theory

Fundamentals and lambda calculus

Functional Programming

Functional Programming Languages (FPL)

More Lambda Calculus and Intro to Type Systems

G Programming Languages - Fall 2012

Introduction to the λ-calculus

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

Lambda Calculus see notes on Lambda Calculus

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

Lambda Calculus LC-1

Pure Lambda Calculus. Lecture 17

VU Semantik von Programmiersprachen

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

Topic III. LISP : functions, recursion, and lists References: Chapter 3 of Concepts in programming languages by J. C. Mitchell. CUP, 2003.

Programming Languages Third Edition

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Chapter 15 Functional Programming Languages

Shell CSCE 314 TAMU. Haskell Functions

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

CMSC 330: Organization of Programming Languages

SOFTWARE ARCHITECTURE 6. LISP

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

Functional programming in LISP

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

Control in Sequential Languages

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

Introduction to ML. Mooly Sagiv. Cornell CS 3110 Data Structures and Functional Programming

CMSC 330: Organization of Programming Languages. Lambda Calculus

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

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

CS 11 Haskell track: lecture 1

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

More Lambda Calculus and Intro to Type Systems

User-defined Functions. Conditional Expressions in Scheme

Documentation for LISP in BASIC

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

Lambda Calculus. Gunnar Gotshalks LC-1

Principles of Programming Languages

1 Lexical Considerations

10.6 Theoretical Foundations

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Scheme Quick Reference

Symbolic Computation and Common Lisp

Lists. Michael P. Fourman. February 2, 2010

Modern Programming Languages. Lecture LISP Programming Language An Introduction

Transcription:

CS320 Principles of Programming Languages Week 4: Functional Programming Jingke Li Portland State University Fall 2017 PSU CS320 Fall 17 Week 4: Functional Programming 1/ 66

Topic List for this Unit Functional programming an important programming paradigm Lambda calculus theoretical foundation Lisp/Scheme language design and programming style ML/Haskell abstract data types (later) PSU CS320 Fall 17 Week 4: Functional Programming 2/ 66

Functional Programming Functional programming is one of the main programming paradigms: Imperative programming Object-oriented programming Functional programming Logic programming Functional programming uses the construction and application of functions as the basic mode of computation. Functional programming s theoretical foundation is not Turing machine; it is lambda calculus. PSU CS320 Fall 17 Week 4: Functional Programming 3/ 66

Functional Programming Advantages Higher Programming Level: Programs written in a functional language typically contain less details about implementation. A functional program describes what to compute instead of how to compute. Easier to Reason and Transform Programs: Features supported by functional languages (e.g. referential transparency) make it easier to analyze and transform a program. For example, macro-expanding a function call is always legal. PSU CS320 Fall 17 Week 4: Functional Programming 4/ 66

Basic Concepts Side effect Referential transparency Higher-order functions First-class functions Pure vs. impure functional languages PSU CS320 Fall 17 Week 4: Functional Programming 5/ 66

Side Effect A function or expression is said to have a side effect if, in addition to producing a value, it also modifies some state. Example: Side-effecting expressions are common in imperative languages: ++i, (a = 3) > b, y = x = 6 // C also exist in some functional languages: (read), (set! x (+ x 1)) // Scheme (print(x); print("\n")) // ML PSU CS320 Fall 17 Week 4: Functional Programming 6/ 66

Side Effect Functions in an imperative language can easily have side effects: void sum(int *s, int a) { *s += a; } int counter() { static c = 0; return ++c; } int safe_divide(int x, int y) { if (y == 0) { printf("error: divisor is 0\n"); return 0; } else return x / y; } Function does not return value, yet content pointed to by s is changed. Function changes program state through a static variable. If y==0, functionchangesprogram state through printf(). PSU CS320 Fall 17 Week 4: Functional Programming 7/ 66

Side Effect However, functions in an imperative language can also be made side-effect free if, they use only non-pointer, call-by-value parameters they reference no non-local variables they have no side-effecting statements (e.g. I/O statements) int average(int a, int b) { return (a + b) / 2; } PSU CS320 Fall 17 Week 4: Functional Programming 8/ 66

Referential Transparency A function or expression is said to be referentially transparent if it can be replaced with its value without changing the behavior of a program. Absence of side effects is a necessary, but not sufficient, condition for referential transparency. Question: Why? Answer: Consider a function that returns the value of a global or environment variable, such as, gettimeofday(). It reads but does not modify the variable, hence it does not have side effects. Yet, it is not referentially transparent. Different calls to the function may return different values. PSU CS320 Fall 17 Week 4: Functional Programming 9/ 66

Referential Transparency Implications: If a function is referentially transparent then its value depends only on its arguments, and it has no side effect. Such a function is called a pure function. Areferentiallytransparentfunctionwithnoparametersmust always return the same value. Thus it is no different than a constant. Examples: Pure math functions, such as gcd(), are referentially transparent. Clibraryfunctionrand() is not because it depends on the state of the machine and previous calls to itself. PSU CS320 Fall 17 Week 4: Functional Programming 10 / 66

Referential Transparency Benefits: Program transformations f(x)+f(x) is always equivalent to 2*f(x). Reasoning about program behavior The result of a function, f(x), can be derived from its input through a sequence of program transformations. This is called equational reasoning. Parallel evaluation All arguments of f(e 1,e 2,...,e k ) can be evaluated in parallel. PSU CS320 Fall 17 Week 4: Functional Programming 11 / 66

Equational Reasoning Similar to using arithmetic properties (such as communitivity and associativity) to simply algebraic expressions However, in addition to built-in operators properties, user-defined functions can also be used as properties for reasoning Example: Consider the reverse function definition in Haskell: reverse :: [a] -> [a] -- type signature reverse [] = [] -- def for empty list case reverse (x:xs) = reverse xs ++ [x] -- def for all other cases We want to show that reverse has no effect on singleton lists, i.e. reverse [x] = [x] for any value x. Reasoning: reverse [x] = reverse (x:[]) -- applying reverse (general case) = reverse [] ++ [x] -- applying reverse (empty list) = [] ++ [x] -- applying ++ = [x] PSU CS320 Fall 17 Week 4: Functional Programming 12 / 66

Higher-Order Functions First-order functions arguments and return value are non-functions,, f Higher-order functions restrictions removed,, f,, f,, f Higher-order function means a function that either takes a function as an argument or returns a function as a result (or both). PSU CS320 Fall 17 Week 4: Functional Programming 13 / 66

First-Class Functions Higher-order-ness is a property of an individual function, while first-class-ness is a property of a programming language. First-class functions mean that functions are being treated as (first-class) values. Specifically, first-class functions mean that: Functions can be passed as arguments to other functions Functions can be returned as results from other functions Functions can be declared in any scope (parallel to variable declarations) Functions can be defined without a name (parallel to literals of other types) PSU CS320 Fall 17 Week 4: Functional Programming 14 / 66

First-Class Functions Imperative languages may support a subset of the first-class features, for example, Pascal allows functions to be defined in nested scopes C allows functions to be passed as arguments and returned as return values But, none of them supports the full set of features. Reason: Need to use heap storage for handling function calls. PSU CS320 Fall 17 Week 4: Functional Programming 15 / 66

Functional Languages Languages that support functional programming style are called functional programming languages. All functional languages treat functions as first-class values. Pure functional languages They further support referential transparency for all functions and expressions (hence no side effect at all). (Example: Haskell) Impure functional languages They allow side effects, although their major mode of computation is still functional. (Example: Scheme) Note that there are also programming languages that have no side effects, but do not support first-class functions. They are not functional languages; they are called single-assignment languages. (Example: SISAL) PSU CS320 Fall 17 Week 4: Functional Programming 16 / 66

Functional Languages Functional languages may look and feel quite differently from imperative languages: They typically don t have many of the features that imperative languages deem essential: mutable variables and assignments mutable data structures such as arrays nested scopes through statement blocks loop constructs Instead, they have immutable variables and definitions immutable lists nested scopes through nested expressions first-class functions recursion lazy evaluation PSU CS320 Fall 17 Week 4: Functional Programming 17 / 66

Immutable Variables Some functional languages (e.g. ML) have assignment-like statements. How do they differ from assignment statements in imperative languages? Compare C++ int x = 5; int &r = x; x = 6; ML val x = 5; val r = ref x; val x = 6; In C++, after the assignment, x s value will be 6, and the reference variable r will point to 6 as well. In ML, changing a variable s value means producing a new copy of the variable, but leaves the old one alone. After the assignment, x s value will be 6, but r still references the old copy of x, i.e.!r = 5. PSU CS320 Fall 17 Week 4: Functional Programming 18 / 66

Immutable Lists What about updating components of a (large) aggregate object? In the following code, what actually happens when an insert is performed? ML fun insert x nil = [x] insert x (h::t) = if h<x then h::(insert x t) else x::h::t; val L = [1,2,4,5,6,7,8,9]; val L = insert 3 L; We get a new list, containing a new element, and a new copy of every other node (even though the values of these nodes haven t changed). Old list still exists. (It should eventually be garbage collected if no longer accessible.) PSU CS320 Fall 17 Week 4: Functional Programming 19 / 66

Nested Scopes Consider a nest of scopes in C, created by statement blocks: int z; { int x = 3, y = 5; { int x = x * 2; z = x + y; } } Question: How can achieve the same effect in a function program? Answer: With nested let constructs, which are expressions. var z = let var x = 3; var y = 5 in let var x = x * 2 in x + y end end; PSU CS320 Fall 17 Week 4: Functional Programming 20 / 66

HigherOrder Function Applications Currying A multi-argument function takes its arguments one at a time. fun mult a b = a * b fun triple = mult 3 The expression mult 3 represents a function, which when applied to a number, triples the value of that number, i.e. triple b mult 3 b Composition Iff : X Y and g : Y Z, then the composition of g and f, g f : X Z, is given by (g o f)(x) = g(f(x)) PSU CS320 Fall 17 Week 4: Functional Programming 21 / 66

Higher-Order Function Applications Map Applies some function to each member of a list and returns the resulting list. map triple [1, 2, 3, 4] = [triple 1, triple 2, triple 3, triple 4] = [3, 6, 9, 12] Fold Computes a value working from the tail of a list to the head (from right to left); at each step, applies the given function to each element and the previously computed result. foldr (+) 0 [2,4,7] = (2 + (4 + (7 + 0))) = 13 sumlist = foldr + 0 multlist = foldr * 1 sumlist [1,2,3,4] = 10 multlist [1,2,3,4] = 24 PSU CS320 Fall 17 Week 4: Functional Programming 22 / 66

Recursion In functional languages, recursions replace loops. Consider the factorial function: fac(n) =if(n = 0) then 1 else n fac(n 1) Scheme (define (fac n) (if (= n 0) 1 (* n (fac (- n 1))))) ML fun fac n = if n=0 then 1 else n * fac(n-1); However, a recursive function in general is more expensive to implement than a loop, because it needs the support of a stack. Compilers for functional languages try very hard to convert recursive functions to better forms, such as the tail-recursive form. PSU CS320 Fall 17 Week 4: Functional Programming 23 / 66

Tail Recursion Tail recursion is a special form of recursion, in which the only recursive call is the last act of the recursive function: // Factorial function, // not tail-recursive int fac(int n) { if (n <= 1) return 1; return n * fac(n-1); } // Tail-recursive, but // not a meaningful function! int g(int n) { if (n <= 1) return 1; return g(n-1); } Property: Any tail-recursive function can be converted to a non-recursive function with an iteration construct; hence can be implemented efficiently. Question: Can we convert the recursive factorial function into a tailrecursive one? The answer is Yes. PSU CS320 Fall 17 Week 4: Functional Programming 24 / 66

Tail Recursion Let s trace the recursive factorial function; at each step, record the cumulative partial result. Step Recursive call Partial result 0 fac(n) 1 1 fac(n-1) n 2 fac(n-2) n*(n-1) 3 fac(n-3) n*(n-1)*(n-2) n-1 fac(1) n*(n-1)* *2 n n! Now let s define a helper function with two parameters, one tracks the recursive call s argument, the other the partial result: helper(k, res) =if(k 1) then helper(k 1, res k) else res Function helper is tail-recursive, and function fac can be defined as: fac(n) =helper(n, 1) PSU CS320 Fall 17 Week 4: Functional Programming 25 / 66

Tail Recursion Here is a C version of the tail-recursive factorial program: int helper(int k, int res) { if (k >= 1) return helper(k-1, res*k); return res; } int fac(int n) { return helper(n, 1); } Amatchingnon-recursive program: int helper(int k, int res) { while (k >= 1) { res = res * k; k--; } return res; } int fac(int n) { return helper(n, 1); } PSU CS320 Fall 17 Week 4: Functional Programming 26 / 66

Tail Recursion Now an ML version: fun fac n = let fun helper(k, res) = if k >= 1 then helper(k-1, res*k) else res in helper(n, 1) end; PSU CS320 Fall 17 Week 4: Functional Programming 27 / 66

Lazy Evaluation A feature that appears in some functional languages. It concerns with how a function s arguments are evaluated. Example: mult(fac(3), fac(4)) Normal (Eager) Evaluation Evaluate arguments before invoking a function call (Think call by value ) 1. eval fac(3) 6; eval fac(4) 24 2. eval mult(6,24) 144 Lazy Evaluation Substitute arguments into a function s body (Think call by name ) 1. reduce mult fac(3) fac(4) 2. reduce fac 6 24 144 PSU CS320 Fall 17 Week 4: Functional Programming 28 / 66

Lazy Evaluation Application Lazy evaluation is useful for handling unbounded lists: [1..] -- defines an unbounded list, but only the -- first element is explicitly named; the -- list generator can produce any other -- element when needed head [1.. ] -- => 1 head (tail [1.. ]) -- => 2 head (map triple [1.. ]) -- => 3 -- the computation is demand-driven, only -- enough computation is performed to -- produce the result PSU CS320 Fall 17 Week 4: Functional Programming 29 / 66

Lambda Calculus An abstract notation for defining computable functions developed in the 1930s by Lorenzo Church. It is a Turing-complete, universal model of computation It is the foundation for Lisp and other functional languages It is also used in theoretical studies of programming languages Lambda calculus consists of a notation for function expressions (λ-expressions) and a number of calculation rules (reductions). PSU CS320 Fall 17 Week 4: Functional Programming 30 / 66

Lambda Expressions A λ-expression can be in one of three forms: M x λx.m MM x λx.m M 1 M 2 Examples: variable, x is a variable name abstraction, denotes a single-argument function application, it s the application of function M 1 to argument M 2 λx.x (λx.x)y λf.λg.λx.f (gx) PSU CS320 Fall 17 Week 4: Functional Programming 31 / 66

Common Conventions Variables are typically represented by lower-case letters; sub-expressions are typically represented by upper-case letters The body of an abstraction extends as far right as possible: λx.mn means λx.(mn) and not (λx.m)n Applications are left associative: XYZ means (XY )Z Nested lambdas may be collapsed together: λx.λy.xyx can be written as λxy.xyx White space is insignificant: XY and XY are exactly the same PSU CS320 Fall 17 Week 4: Functional Programming 32 / 66

Functions of Multiple Arguments A function f (x, y) of two arguments may be represented by a function λx.(λy.m) which is of a single argument that, when applied, returns a second function that accepts a second argument and then computes a result in the same way as f. Using the common convention, the above lambda expression can be simplified: λx.(λy.m) =λx.λy.m = λxy.m This idea of defining functions with multiple arguments is called currying, and is widely used in functional languages. PSU CS320 Fall 17 Week 4: Functional Programming 33 / 66

Values and Operators Pure lambda calculus has only variables and functions, nothing else. However, values, operators, and other constructs can be defined by λ-expressions. Church encoding for integers Define each integer as a function of two parameters, f and x. The integer s value is encoded as the number of times f is applied to x. Number Function Definition Lambda Expression 0 0(f, x) =x 0=λfx.x 1 1(f, x) =f (x) 1=λfx.fx 2 2(f, x) =f (f (x)) 2=λfx.f (fx) 3 3(f, x) =f (f (f (x))) 3=λfx.f (f (fx))... n n(f, x) =f n (x) n = λfx.f n x (+ mn) fx= f m+n x = mf (nfx) +=λmnfx.mf (nfx) ( mn) fx= f m n x =(f n ) m x = m(nf )x = λmnfx.m(nf )x PSU CS320 Fall 17 Week 4: Functional Programming 34 / 66

Values and Operators Church encoding for Booleans Define true and false as functions of two parameters: true selects the first parameter, and false selects the second parameter. T = λxy.x F = λxy.y not = λx.xft and = λxy.xyf or = λxy.xty Let s verify the definition of not. First, notice that TPQ =(λxy.x)pq (λy.p)q P FPQ =(λxy.y)pq (λy.y)q Q Now not T = (λx.xft)t TFT F not F = (λx.xft)f FFT T PSU CS320 Fall 17 Week 4: Functional Programming 35 / 66

Applied Lambda Calculus To make the task of specifying computation easier, and make long lambda expressions more readable, we would like to include values and operators into lambda calculus. The result: Applied Lambda Calculus = Pure Lambda Calculus +ValuesandOperators Applied lambda calculus is exactly equivalent to pure lambda calculus At same time, it looks more like a programming language PSU CS320 Fall 17 Week 4: Functional Programming 36 / 66

Let Binding Recall the let binding, let x = M in N, which declares that x has value M in the body N. It can be regarded as syntactic sugar for a combination of lambda abstraction and application: let x = M in N (λx.n)m PSU CS320 Fall 17 Week 4: Functional Programming 37 / 66

Y Combinator Question: A lambda abstraction defines an anonymous function. How can one define recursion with only anonymous functions? Answer: Y combinator (discovered by Haskell B. Curry) Y = λt.(λx.t(xx))(λx.t(xx)) Yf =(λx.f (xx))(λx.f (xx)) = f ((λx.f (xx))(λx.f (xx))) = f (Yf ) Yf = f (Yf ) Thus Yf is a fixed point of any function f. PSU CS320 Fall 17 Week 4: Functional Programming 38 / 66

Y Combinator Example: Define an anonymous factorial function. 1. Start with the normal self-recursive form: fac = λn.if (n = 0) then 1 else n fac(n 1) 2. Define a function G to represent the name fac a parameter: G = λf.λn.if (n = 0) then 1 else n f (n 1) 3. Hence fac = Gfac 4. We need to find a fixed point of G usethey combinator: Y G = G(Y G) fac = Y G = (λt.(λx.t(x x))(λx.t(x x))) λf.λn.if (n = 0) then 1 else n f (n 1) * Constructs such as if-then-else can also be defined by lambda expression. PSU CS320 Fall 17 Week 4: Functional Programming 39 / 66

Performing Computation Applied lambda calculus is very much a programming language. We can define functions and expressions for real computation problems. Question: How is a lambda calculus program executed? For instance, if we write the expression fac 5, how do we get the result 120? Answer: Lambda calculus uses two reductions to perform computation: α-reduction β-reduction PSU CS320 Fall 17 Week 4: Functional Programming 40 / 66

Free and Bound Variables Variables are either free or bound. The symbol λ is a binding operator. Example: Variable x is free in expression x +3 Variable x is bound in expression λx.x +3 We need to be careful about the scope of variables a variable can be both free and bound in a single expression. Example: In the following expression, the first y is bound, the second y is free: (λxy.y + 3)(x + y) PSU CS320 Fall 17 Week 4: Functional Programming 41 / 66

Alpha Reduction We can rename bound variables without changing the semantics of a lambda expression. Example: Function λx.x + y is the same as λz.z + y. The two expressions are said to be α-equivalent The process of renaming is called α-reduction We use [y/x]m to mean replace every occurrence of x in M with y. With this notation, we can express α-reduction formally as λx.m = λy.[y/x]m (α-reduction) PSU CS320 Fall 17 Week 4: Functional Programming 42 / 66

Beta Reduction The process of performing a function application is called β-reduction. It is the main computation rule in lambda calculus. (λx.m)n =[N/x]M (β-reduction) The two expressions are called β-equivalent Examples: (λx.x)y =[y/x]x = y (λx.xy)y =[y/x]xy = yy (λx.xy)λx.x =[λx.x/x]xy =(λx.x)y = y PSU CS320 Fall 17 Week 4: Functional Programming 43 / 66

Beta Reduction Sometimes we need to perform α-reduction before we can perform β-reduction. Example: Consider (λyx.x + y)(x + 1). Wrong: (λyx.x + y)(x + 1) =[x +1/y]λx.x + y = λx.x + x +1 Free variable x becomes bound after reduction. Correct: (λyx.x + y)(x + 1) =(λyz.[z/x]x + y)(x + 1) =(λyz.z + y)(x + 1) =[x +1/y]λz.z + y = λz.z + x +1 Free variable x stays free after reduction. PSU CS320 Fall 17 Week 4: Functional Programming 44 / 66

Normal Form and Confluence Normal Form Aλ-expression is in normal form if it cannot be further reduced by β-reduction. Example: (λy.yy)((λx.xx)a) ((λx.xx)a)((λx.xx)a) (aa)(aa) Confluence Regardless of the order in which the reductions are performed, a λ-expression always gets reduced to a unique normal form. Example: Another reduction sequence leads to the same normal form. (λy.yy)((λx.xx)a) (λy.yy)(aa) (aa)(aa) Evaluation in lambda calculus is order independent. PSU CS320 Fall 17 Week 4: Functional Programming 45 / 66

Lisp The first functional language, developed by John McCarthy in 1960. directly based on lambda calculus Very simple syntax prefix notation with (lots of) parentheses very few reserved words and predefined constructs Clean semantics described by a simple abstract machine model (written in Lisp itself) Historical contributions abstract view of memory cells instead of linear addresses programs as data sharing the same syntax garbage collection PSU CS320 Fall 17 Week 4: Functional Programming 46 / 66

Lisp Dialects Lisp has two main dialects: Common Lisp: large and complex allows both static and dynamic scopes large number of data structures arrays, records, complex numbers, packages, etc. Scheme: keeps Lisp s simple syntax and semantics static scope (different from Lisp) We ll use Scheme to show our examples. PSU CS320 Fall 17 Week 4: Functional Programming 47 / 66

Scheme Syntax All programs and data in Scheme are considered expressions. There are (only) two types of expressions: atoms and lists. expr list atom list ( {expr} ) atom number string symbol char boolean PSU CS320 Fall 17 Week 4: Functional Programming 48 / 66

Atoms Numbers: 42, -12, 3.14 Strings: "hello" Symbols: x, y, +, * Characters: #\a, #\b, #\c Booleans: #t, #f Value of an atom is just the object itself. PSU CS320 Fall 17 Week 4: Functional Programming 49 / 66

Atoms Built-in functions for manipulating atoms: Numbers: +, -, *, /, <, >, <=, >=, = Booleans: and, or, not Strings: string-length, string=? Question: These function names themselves are expressions. What are their values? Answer: Their values are (anonymous) functions. + #{procedure 110 +} * #{procedure 107 *} PSU CS320 Fall 17 Week 4: Functional Programming 50 / 66

List Expressions Lists are used to represent both data objects and expressions. List construction: (cons a ()) (a) (cons b (cons a ()) (b a) (cons b a) (b. a) (list a b c) (a b c) Notice the difference between (b a) and (b. a). Thelatteriscalled a dotted pair. From the structure point of view, lists are just special forms of nested dotted pairs: (a b c d) = (a. (b. (c. (d. ())))) List De-construction: (car (a b c)) a (cdr (a b c)) (b c) PSU CS320 Fall 17 Week 4: Functional Programming 51 / 66

List Expressions When a list is representing an expression, its first item is special it either encodes a special action or represents a function. List expressions whose first item is a keyword are called special forms. Example: (define x 5) (lambda (x) (* x x)) These are some important keywords: define, lambda, if, cond, let, quote List expressions in the other form represent function applications. Example: (+ x y) (average x y) PSU CS320 Fall 17 Week 4: Functional Programming 52 / 66

List Expressions Arithmetic and logical expressions take the prefix form: (+ 1 2), (- x y), (not x) Most operators can take one or more operands: (+ 1), (+ 1 2), (+ 1 2 3 4 5),... (- 1), (- 1 2), (- 1 2 3 4 5),... // subtract from 1st oprnd (or x), (or x y), (or x y z w v),.. A few operators are also defined where there is no operand: (+) => 0, (*) => 1, (and) => #t, (or) => #f A comparison between C and Scheme expressions: C: 1 + 2 * 3 4 + 5 + 6 7-8 - 9 (a==b) && (a!=0) (a b) c Scheme: (+ 1 (* 2 3)) (+ 4 5 6) (- 7 8 9) (and (= a b) (not (= a 0))) (or a b c) PSU CS320 Fall 17 Week 4: Functional Programming 53 / 66

Scheme Semantics The meaning of a Scheme expression is given by the evaluation rules: 1. Atomic literals evaluate to themselves 2. Symbols other than keywords are variables; their values are looked up in the current environment 3. Special-form list expressions are evaluated by pre-defined special rules 4. Other list expressions are evaluated as function applications 4.1 Evaluate all of the subexpressions of the list (in any order) 4.2 Apply the function to the values of the arguments and return the result as the list s value Rules for function application: 1. If function is built-in, just do it 2. If function is user-defined, then evaluate its body with each formal parameter replaced by the corresponding actual argument value PSU CS320 Fall 17 Week 4: Functional Programming 54 / 66

Lambda Special Form Lambda special form is used to define function. It s directly taken from lambda calculus. Syntax: (lambda ({symbol}) expr) It can be used to define functions with any number of parameters. (lambda () 2) (lambda (x) (* x x)) (lambda (x y) (/ (+ x y) 2)) Semantics: No operands are evaluated The value of a lambda expression is a procedure object, whose parameters are given in the 1st operand, and its body is given by the 2nd operand PSU CS320 Fall 17 Week 4: Functional Programming 55 / 66

Define Special Form Define special form is used to bind name to value. Syntax: (define symbol expr) (define x 5) (define average (lambda (x y) (/ (+ x y) 2))) Semantics: Evaluate the 2nd operand (only) Bind the value to the name given in the 1st operand The value of the define expression itself is undefined Note: Pre-defined symbols can be bound to new values. (define + *) ; redefine + (+ 5 5) ; = 25 (!) This is not recommended! PSU CS320 Fall 17 Week 4: Functional Programming 56 / 66

If Special Form If special form is used for controlled selection between two values. Syntax: (if expr 1 expr 2 [expr 3 ]) (if (= a 0) 0 (/ 1 a)) ; if a=0 return 0 ; else return 1/a (if (list? x) (car x)) ; if x is a list, ; return its first item Semantics: Evaluate expr 1 first, if the value is true, evaluate expr 2 and use its value as the if expression s value else evaluate expr 3 and use its value as the if expression s value; if expr 3 is absent, the if expression s value is undefined PSU CS320 Fall 17 Week 4: Functional Programming 57 / 66

Cond Special Form Cond special form is used for controlled selection among multiple values. Syntax: (p i and e i all denote expressions) (cond (p 1 e 1 ) (p n e n ) [(else e n+1 )]) (cond ((< 2 1) 1) ((< 1 2) 2)) ; has value 2 (cond ((< 2 1) 1) ((< 3 2) 2)) ; is undefined (cond (diverge 1) (true 0)) ; is undefined (assume ; diverge is undefined) (cond (true 0) (diverge 1)) ; has value 0 Semantics: Evaluate p 1,...,p n in order The cond expression s value is the value of e k if p k is true and if for every i < k, thevalueofp i is false The exression is undefined if p 1,...,p k 1 are false and p k is undefined, regardless of the values of p k+1,...,p n If none of these p i sistrueandthereisanelse expr at the end, then the expression s value is the value of e n+1 ; otherwise it s undefined PSU CS320 Fall 17 Week 4: Functional Programming 58 / 66

Let Special Form Let special form is used to bind names to values within an expression. It provides a local environment and scope for a set of variable names. Syntax: (let ((var 1 expr 1 ) (var n expr n )) expr n+1 ) The first expr is a binding list. (let ((a 2) (b 3)) (+ a b)) (let ((average (lambda (x y) (/ (+ x y) 2)))) (average 96 99)) Semantics: Evaluate expr 1,...,expr n (in no particular order) Bind var 1,...,var n to their corresponding expr s value Evaluate expr n+1 ; use its value as the let expression s value Note: Let can be defined by lambda expression: (let (x val) expr) ((lambda (x) expr) val) PSU CS320 Fall 17 Week 4: Functional Programming 59 / 66

Quote Special Form Quote special form is used for representing data literals. Syntax: (quote expr) or expr 'a ; => symbol a (quote "hi") ; => string "hi" (quote (+ 2 3)) ; => (list '+ '2 '3) Semantics: No evaluation needs to be performed Quote expression s value is the literal form of expr PSU CS320 Fall 17 Week 4: Functional Programming 60 / 66

The Eval Function The Scheme eval function takes a quoted expression, and evaluates it. (eval '(+ 2 3)) ; => 5 (define a 'b) (define b 'c) (define c 50) (eval a) ; => c (eval (eval a)) ; => 50 PSU CS320 Fall 17 Week 4: Functional Programming 61 / 66

Programs as Data With quote and eval, we can easily construct a program as a list and evaluate it, and do this processing within a program. Example: John s bank account has an initial balance (amnt). He made a sequence of withdraws, and the withdraw amounts are kept in a list (wlist). Now John wants to calculate the remaining balance in his account. Conventional approach: Subtracting each withdraw amount from the initial amount. (define (balance amnt wlist) (cond ((null? wlist) amnt) (else (balance (- amnt (car wlist)) (cdr wlist))))) Assume amnt = 800and wlist = (30 40 50) (balance 800 (30 40 50)) (balance 770 (40 50)) (balance 730 (50)) (balance 680 ()) amnt = 680 PSU CS320 Fall 17 Week 4: Functional Programming 62 / 66

Programs as Data Programs-as-data approach: Constructing a list with the subtraction operator; then evaluate the list. (define (balance amnt wlist) (cond ((null? wlist) amnt) (else (eval (cons '- (cons amnt wlist)))))) Assume amnt = 800and wlist = (30 40 50) (balance 800 (30 40 50)) (eval (cons - (cons 800 (30 40 50)))) (eval (cons - (800 30 40 50))) (eval (- 800 30 40 50)) 780 PSU CS320 Fall 17 Week 4: Functional Programming 63 / 66

Recursion Revisit It s easy to define recursive functions in Scheme: (define (! n) (if (= n 0) 1 (* n (! (- n 1))))) (! 5) => 120 However, Defining factorial through the Y-combinator also works: (define Y (lambda (f) (let ((w (lambda (x) (f (lambda (n) ((x x) n)))))) (w w)))) (define G (lambda (f) (lambda (n) (if (= n 0) 1 (* n (f (- n 1))))))) ((G (Y G)) 5) => 120 PSU CS320 Fall 17 Week 4: Functional Programming 64 / 66

Scheme Interpreter in Scheme Recall that an interactive interpreter has a read-eval-print loop (REPL) program structure. Scheme has built-in support for all four operations. So it is super easy to write a Scheme interpreter in Scheme: (define (repl) (display "repl>") (write (eval (read))) (repl)) ; display a prompt ; read-eval-print an expr ; loop (tail-recursive call) Of course, the hard work is done by the eval function. But even if we need to write it ourselves, it s not that hard since Scheme s syntax is very simple! PSU CS320 Fall 17 Week 4: Functional Programming 65 / 66

Summary Functional programming is one of the main programming paradigms. It relies on functions and expressions for specifying computation. Lambda calculus provides the theoretical foundation for functional programming. It is a universal model of computation any computable function can be expressed by it. The lambda form of anonymous function definition has been widely adopted in programming languages today, including imperative languages. Lisp is a very important functional language. Its unified syntax allows seamless switching between expressions and data objects. We have studied some important concepts, such as: side effect, referential transparency, higher-order functions, first-class functions, α and β reductions. PSU CS320 Fall 17 Week 4: Functional Programming 66 / 66