lecture 5: functional programming
TRANSCRIPT
![Page 1: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/1.jpg)
TI1220 2012-2013Concepts of Programming Languages
Eelco Visser / TU Delft
Lecture 5: Functional Programming
![Page 2: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/2.jpg)
![Page 3: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/3.jpg)
Around 1959, he invented so-called "garbage collection" methods to solve problems in Lisp. Based on the lambda calculus, Lisp soon became the programming language of choice for AI applications after its publication in 1960.
John McCarthy (September 4, 1927 – October 24, 2011) was an American computer scientist and cognitive scientist. He coined the term "artificial intelligence" (AI), developed the Lisp programming language family, significantly influenced the design of the ALGOL programming language, popularized timesharing, and was very influential in the early development of AI.
http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
![Page 4: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/4.jpg)
OutlineFrom the lab:
Unit testingGraded assignment 1
Functional objects in ScalaPattern matchingRecursion and inductionAlgebraic data typesBinary treesAlgebraic data types in C
![Page 5: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/5.jpg)
Messages from the Lab
![Page 6: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/6.jpg)
Tests
• check that your code is correct
• regression testing: don’t make the same mistake twice
Coverage
• a test for each representative case
Test-driven development
• (1) define tests for representative cases
• (2) write code
• (3) test
![Page 7: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/7.jpg)
import org.scalatest.Suite
class <NameOfTestClass> extends Suite { import <ClassUnderTest>._ def <testNameOfTest> { expect(<expected result>) { <computation> } }}
Unit Testing in Scala
![Page 8: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/8.jpg)
/* import test framework .h */#include "solution.c"#include "CuTest.h"#include "CuJoin.h"
/* your imported libraries */#include <string.h>
/* signatures of all functions being tested */char* wc(char* data);
/* defined tests */void test_1(CuTest *tc) { char* wcout = wc("hello\n world"); char* expected = "2 2 10 12"; CuAssertTrue(tc, !strcmp(wcout,expected));}/* hook all your tests into the harness */void testHooker(CuSuite* intoSuite){ SUITE_ADD_TEST(intoSuite, test_1);}
Unit Testing in C
![Page 9: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/9.jpg)
test("Changing properties", function() { var obj = {x : 3}; expect(5); ok(changeProp, "function exists"); equal(obj.x, 3); equal(obj.y, undefined); changeProp(obj); equal(obj.x, 42); equal(obj.y, 9);});
Unit Testing in JavaScript
![Page 10: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/10.jpg)
Graded Assignment 1Algebraic datatypes in CDynamic dispatch in C
Important datesDeadline: April 2, 2013 23:59Extension: April 5, 2013 23:59
Submitting after extension date is not possibleMaximum penalty for submitting after deadline: 6 pointsMinimum grade needed: 4Grade: 70% unit tests, 30% check listsGrade for GAs: average of four assignments
![Page 11: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/11.jpg)
abstract class XMLcase class Text(t: String) extends XMLcase class Elem(tag: String, elems: List[XML]) extends XML
object Solution {
def text(elems1: List[XML]): List[XML] = elems1.flatMap(_ match { case t@Text(_) => List[XML](t) case Elem(_, elems2) => text(elems2) }) }
Algebraic Datatypes in C
translate this Scala program to an equivalent C program
![Page 12: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/12.jpg)
// values
abstract class Value { def value: Int def isFailure: Boolean def +(that: Value): Value def *(that: Value): Value}
object LookupFailure extends Value { def value: Int = 0 def isFailure: Boolean = true def +(that: Value) = LookupFailure def *(that: Value) = LookupFailure}
class IntValue(v : Int) extends Value { val value = v def isFailure: Boolean = false def +(that: Value) = that match { case v: IntValue => new IntValue(value + v.value) case _ => LookupFailure } def *(that: Value) = that match { case v: IntValue => new IntValue(value * v.value) case _ => LookupFailure }}
translate this Scala program to an equivalent C program
Dynamic Dispatch in C
![Page 13: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/13.jpg)
// environments
abstract class Env { def lookup(x: String): Value}class MtEnv extends Env { def lookup(x: String): Value = LookupFailure}class Bind(key: String, value: Int, env: Env) extends Env { def lookup(x: String): Value = if(x == key) new IntValue(value) else env.lookup(x);}
Dynamic Dispatch in C
![Page 14: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/14.jpg)
// expressions
abstract class Exp { def eval(env: Env): Value; override def toString: String}
class IntExp(value: Int) extends Exp { def eval(env: Env) = new IntValue(value) override def toString = value.toString}
class VarExp(name: String) extends Exp { def eval(env: Env) = env.lookup(name) override def toString = name}
class PlusExp(left: Exp, right: Exp) extends Exp { def eval(env: Env) = left.eval(env) + right.eval(env) override def toString = "(" + left.toString + " + " + right.toString + ")"}
class MulExp(left: Exp, right: Exp) extends Exp { def eval(env: Env) = left.eval(env) * right.eval(env) override def toString = "(" + left.toString + " * " + right.toString + ")"}
Dynamic Dispatch in C
![Page 15: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/15.jpg)
Functional Programming (in Scala)
![Page 16: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/16.jpg)
Ingredients of functional programming
Immutable objects
Pattern matching
Inductive (algebraic) data types
Recursive functions
First-class functions (next week)
![Page 17: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/17.jpg)
Functional Objects in Scala
![Page 18: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/18.jpg)
functional object: the fields of an object are immutable
![Page 19: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/19.jpg)
Example: Rational Numbers
• Rational = Int x Int
• Notation: numerator/denominator
• Addition
• example: 1/2 + 2/3 = 3/6 + 4/6 = (3 + 4)/6 = 7/6
• general: n1/d1 + n2/d2 = (n1*d2 + n2*d1) / (d1*d2)
• Multiplication
• n1/d1 + n2/d2 = (n1 * n2) / (d1 * d2)
• Division
• n1/d1 / n2/d2 = n1/d2 * d2/n2
![Page 20: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/20.jpg)
class Rational(n: Int, d: Int) { println("Created " + n + "/" + d)}
scala> new Rational(1, 2)Created 1/2res0: Rational = Rational@2d83e895
class parameters
Constructing a Rational
![Page 21: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/21.jpg)
Immutable object trade-offs
Advantages
• easier reasoning
• pass around freely (no risk of undesired mutations)
• cannot be changed concurrently in two threads
• immutable object make safe hash table keys
Disadvantages
• copying large object graphs vs in-place update
![Page 22: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/22.jpg)
class Rational(n: Int, d: Int) { override def toString = n + "/" + d}
Overriding Methods
scala> val half = new Rational(1, 2)half: Rational = 1/2
![Page 23: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/23.jpg)
class Rational(n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d}
scala> val half = new Rational(1, 0)java.lang.IllegalArgumentException: requirement failed
Checking Pre-conditions
![Page 24: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/24.jpg)
Adding Rationals Functionally
class Rational(n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)}
![Page 25: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/25.jpg)
$ fsc Rational.scala Rational.scala:5: error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^Rational.scala:5: error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^two errors found
Visibility of Class Parameters
class Rational(n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)}
![Page 26: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/26.jpg)
class Rational(n: Int, d: Int) { require(d != 0) val numer: Int = n val denom: Int = d override def toString = numer + "/" + denom def add(that: Rational): Rational = new Rational( numer * that.denom + that.numer * denom, denom * that.denom)}
Functional Fields
scala> new Rational(1,2) add new Rational(2,3)res0: Rational = 7/6
![Page 27: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/27.jpg)
class ImperativeRational(n: Int, d: Int) { require(d != 0) var numer: Int = n var denom: Int = d override def toString = numer + "/" + denom def add(that: ImperativeRational) { numer = numer * that.denom + that.numer * denom; denom = denom * that.denom; }}
scala> val half = new ImperativeRational(1, 2)half: ImperativeRational = 1/2
scala> val twothirds = new ImperativeRational(2,3)twothirds: ImperativeRational = 2/3
scala> half.add(twothirds)
scala> halfres1: ImperativeRational = 7/6
Non-functional Objects
Destructive Update
![Page 28: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/28.jpg)
def lessThan(that: Rational) = this.numer * that.denom < that.numer * this.denom
def max(that: Rational) = if (this.lessThan(that)) that else this
this: optional when referring to fields
Self References
![Page 29: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/29.jpg)
class Rational(n: Int, d: Int) { require(d != 0) val numer = n val denom = d def this(n: Int) = this(n, 1) // auxiliary constructor ...}
Auxiliary Constructors
scala> new Rational(6)res1: Rational = 6/1
![Page 30: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/30.jpg)
class Rational(n: Int, d: Int) { require(d != 0) private val g = gcd(n.abs, d.abs) val numer = n / g val denom = d / g ... private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)}
Private Fields and Methods
scala> new Rational(6,42)res1: Rational = 1/7
![Page 31: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/31.jpg)
def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
scala> new Rational(1,2).add(new Rational(2,3))res0: Rational = 7/6scala> new Rational(1,2) add new Rational(2,3) res0: Rational = 7/6
Using Functions as Infix Operators
![Page 32: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/32.jpg)
def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
scala> val d = a + b * c d: Rational = 11/14scala> val d = a.+(b.*(c))d: Rational = 11/14scala> val d = a * b + c d: Rational = 16/21scala> val d = (a.*(b)).+(c)d: Rational = 16/21
Operator Identifiers
Invoking Operators
![Page 33: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/33.jpg)
How many Rational objects are created while executing:
class Rational(n: Int, d: Int) { require(d != 0) val numer: Int = n val denom: Int = d override def toString = numer + "/" + denom def +(that: Rational): Rational = new Rational( numer * that.denom + that.numer * denom, denom * that.denom)}var half = new Rational(1,2)half = half + half + half
(a) 1(b) 2(c) 3(d) 4 Quiz
![Page 34: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/34.jpg)
Alphanumeric identifier
• identifier: [$A-Za-z_][$A-Za-z_0-9]* ($ reserved for Scala compiler)
• camel-case convention: toString, HashSet
Operator identifier
• Unicode set of mathematical symbols(Sm) or other symbols(So), or to the 7-bit ASCII characters that are not letters, digits, parentheses, square brackets, curly braces, single or double quote, or an underscore, period,semi-colon, comma, or back tick character.
Literal Identifier
• arbitrary string enclosed in back ticks (` . . . `).Identifier Syntax
![Page 35: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/35.jpg)
Method Overloading
scala> val c = new Rational(3,7)c: Rational = 3/7
scala> c * 2res1: Rational = 6/7
def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
def *(i: Int): Rational = new Rational(numer * i, denom)
In a method call, the compiler picks the version of an overloaded method that correctly matches the
types of the arguments.
![Page 36: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/36.jpg)
Method Overloading does not apply to this
def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
def *(i: Int): Rational = new Rational(numer * i, denom)
scala> 2 * c <console>:7: error: overloaded method value * with alternatives: (Double)Double <and> (Float)Float <and> (Long)Long <and> (Int)Int <and> (Char)Int <and> (Short)Int <and> (Byte)Int cannot be applied to (Rational) 2 * c ^
![Page 37: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/37.jpg)
Implicit Conversions
implicit def intToRational(x: Int) = new Rational(x)
scala> 2 * c res4: Rational = 6/7
def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
def *(i: Int): Rational = new Rational(numer * i, denom)
![Page 38: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/38.jpg)
Functional Objects - Summary
Immutable objects
• class parameters
• immutable fields (val)
• methods don’t change object, but return value
Natural, concise notation
• methods as infix operators, operator identifiers
• method overloading
• implicit conversion
![Page 39: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/39.jpg)
Pattern Matching
![Page 40: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/40.jpg)
Match is similar to Java switch. Differences:
• Match is expression: returns a value
• Alternatives never fall through
• MatchError when no pattern matches
Scala’s Match
e0 match { case 1 => e1; case 2 => e2; case _ => e3 }
![Page 41: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/41.jpg)
val firstArg = if (args.length > 0) args(0) else ""firstArg match { case "salt" => println("pepper") case "chips" => println("salsa") case "eggs" => println("bacon") case _ => println("huh?")}
Choosing between Actions
val firstArg = if (!args.isEmpty) args(0) else ""val friend = firstArg match { case "salt" => "pepper" case "chips" => "salsa" case "eggs" => "bacon" case _ => "huh?" }println(friend)
Choosing between Values
![Page 42: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/42.jpg)
Constant Patterns
def describe(x: Any) = x match { case 5 => "five" case true => "truth" case "hello" => "hi!" case Nil => "the empty list" case _ => "something else"}
expr match { case 0 => "zero" case somethingElse => "not zero: " + somethingElse}
Pattern Variables
![Page 43: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/43.jpg)
Recursion and Induction
![Page 44: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/44.jpg)
Natural number
• 0 is a number
• if n is a number then n + 1 is a number
• nothing else is a natural number
Inductive Definitions
![Page 45: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/45.jpg)
def property(n: Int): Boolean = n match { case 0 => // base case case m => ... property (m - 1) ... // recursive case for n + 1 }
def f(n: Int): Int = n match { case 0 => // base case case m => ... f(m - 1) ... // recursive case for n + 1 }
Induction Principle
![Page 46: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/46.jpg)
def isEven(n: Int): Boolean = n match { case 0 => ? case m => ? } def isOdd(n: Int): Boolean = n match { case 0 => ? case m => ? }
![Page 47: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/47.jpg)
def isEven(n: Int): Boolean = n match { case 0 => true case m => isOdd(m - 1) } def isOdd(n: Int): Boolean = n match { case 0 => false case m => isEven(m - 1) }
![Page 48: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/48.jpg)
def power(n: Int, exp: Int): Int = exp match { case 0 => ? case m => ?
}
![Page 49: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/49.jpg)
def power(n: Int, exp: Int): Int = exp match { case 0 => 1 case m => if(exp % 2 == 1) n * power(n, m - 1) else power(n * n, m / 2) }
![Page 50: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/50.jpg)
Algebraic Data Types
![Page 51: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/51.jpg)
Natural number
• 0 is a number
• if n is a number then n + 1 is a number
List
• Empty list is a list
• If L is a list then adding an element in front of L produces a list
Inductive Data Structures
![Page 52: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/52.jpg)
abstract class IntList
case class Nil() extends IntList
// Nil() is a list (the empty list)
case class Cons(hd: Int, tail: IntList) extends IntList
// if hd is an Int and tail is an IntList// then Cons(hd, tl) is an IntList
Scala: Case ClassesNil()Cons(1, Nil())Cons(2, Cons(1, Nil()))Cons(1, Cons(2, Cons(3, Nil())))...
![Page 53: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/53.jpg)
abstract class IntListcase class Nil() extends IntListcase class Cons(hd: Int, tail: IntList) extends IntList
def f(xs: IntList): T = xs match { case Nil() => // base case case Cons(x, ys) => ... f(ys) ... // recursive case }
Induction Principle for IntList
![Page 54: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/54.jpg)
def length(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }
length of list xs
![Page 55: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/55.jpg)
def length(xs: IntList): Int = xs match { case Nil() => 0 case Cons(x, ys) => 1 + length(ys) }
length of list xs
![Page 56: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/56.jpg)
def sum(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }
sum of the integers in xs
![Page 57: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/57.jpg)
def sum(xs: IntList): Int = xs match { case Nil() => 0 case Cons(x, ys) => x + sum(ys) }
sum of the integers in xs
![Page 58: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/58.jpg)
def product(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }
product of the integers in xs
![Page 59: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/59.jpg)
def product(xs: IntList): Int = xs match { case Nil() => 1 case Cons(x, ys) => x * product(ys) }
product of the integers in xs
![Page 60: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/60.jpg)
def append(xs: IntList, ys: IntList): IntList = xs match { case Nil() => ? case Cons(x, zs) => ? }
append elements of ys to xs
![Page 61: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/61.jpg)
def append(xs: IntList, ys: IntList): IntList = xs match { case Nil() => ys case Cons(x, zs) => Cons(x, append(zs, ys)) }
append elements of ys to xs
![Page 62: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/62.jpg)
def reverse(xs: IntList): IntList = xs match { case Nil() => ? case Cons(y, ys) => ? }
elements of xs in reverse
![Page 63: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/63.jpg)
def reverse(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => append(reverse(ys), Cons(y, Nil())) }
elements of xs in reverse
![Page 64: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/64.jpg)
def reverse(xs: IntList): IntList = reverseAcc(xs, Nil()) def reverseAcc(xs: IntList, rest: IntList): IntList = xs match { case Nil() => rest case Cons(y, ys) => reverseAcc(ys, Cons(y, rest)) }
reverse in linear time using accumulator
def reverse(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => append(reverse(ys), Cons(y, Nil())) }
![Page 65: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/65.jpg)
def filterEven(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => if(y % 2 == 0) Cons(y, filterEven(ys)) else filterEven(ys) }
the list of elements of xs that are even
![Page 66: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/66.jpg)
def insert(x: Int, xs: IntList): IntList = xs match { case Nil() => Cons(x, Nil()) case Cons(y, ys) => if(x < y) Cons(x, Cons(y, ys)) else Cons(y, insert(x, ys)) } def isort(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => insert(y, isort(ys)) }
sort elements in ascending order
![Page 67: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/67.jpg)
def msort(xs: IntList): IntList = { val n = lenght(xs) / 2 n match { case 0 => xs case _ => val (as, bs) = splitAt(xs, n) merge(msort(as), msort(bs)) }}
Merge Sort
def splitAt(xs: IntList, n: Int): (IntList, IntList) = xs match { case Nil() => (Nil(), Nil()) case Cons(y, ys) => n match { case 0 => (Nil(), xs) case _ => val (as, bs) = splitAt(ys, n - 1) (Cons(y, as), bs) } }
![Page 68: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/68.jpg)
define merge(xs: IntList, ys: IntList): IntList = xs match { case Nil() => ys case Cons(a, as) => ys match { case Nil() => xs case Cons(b, bs) => if(a < b) Cons(a, merge(as, ys)) else Cons(b, merge(xs, bs)) } }
Merge Sort
![Page 69: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/69.jpg)
abstract class IntListcase class Nil() extends IntListcase class Cons(hd: Int, tail: IntList) extends IntList
def f(xs: IntList): T = xs match { case Nil() => // base case case Cons(x, ys) => ... f(ys) ... // recursive case }
Induction Principle for IntList
![Page 70: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/70.jpg)
Binary Trees
![Page 71: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/71.jpg)
abstract class BinTree
case class Empty() extends BinTree
case class Node(left: BinTree, value: Int, right: BinTree) extends BinTree
Empty()
Node(Empty(), 42, Empty())
Node(Empty(), 5, Node(Empty(), 42, Empty()))
Node(Node(Empty(), 2, Empty()), 5, Node(Empty(), 42, Empty()))
def f(t: BinTree): A = t match { case Empty() => ... case Node(t1, i, t2) => ... f(t1) ... f(t2) ... }
![Page 72: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/72.jpg)
def replace(x: Int, y: Int, t: BinTree): BinTree = t match { case Empty() => ? case Node(l, n, r) => ?
}
replace occurrence of x by y
![Page 73: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/73.jpg)
def replace(x: Int, y: Int, t: BinTree): BinTree = t match { case Empty() => Empty() case Node(l, n, r) => Node( replace(x, y, l), if(n == x) y else n, replace(x, y, r) ) }
replace occurrence of x by y
![Page 74: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/74.jpg)
def toList(t: BinTree): IntList = t match { case Empty() => ? case Node(l, n, r) => ?}
transform binary tree to list
![Page 75: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/75.jpg)
def toList(t: BinTree): IntList = t match { case Empty() => List() case Node(l, n, r) => append(toList(l), Cons(n, toList(r)))}
transform binary tree to list
![Page 76: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/76.jpg)
Invariant:
Node(t1, n, t2)- all numbers in t1 are smaller than n- all numbers in t2 are larger than n
Functions:def insert(x: Int, t: BinTree): BinTreedef lookup(x: Int, t: BinTree): Boolean
Correctnesslookup(x, insert(x, t)) == true
Binary Search Trees
![Page 77: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/77.jpg)
def lookup(x: Int, t: BinTree): Boolean = { t match { case Empty() => ? case Node(left, value, right) => ?
} }
Lookup in Binary Search Tree
![Page 78: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/78.jpg)
def lookup(x: Int, t: BinTree): Boolean = { t match { case Empty() => false case Node(left, value, right) => if(x < value) lookup(x, left) else if (x > value) lookup(x, right) else true } }
Lookup in Binary Search Tree
![Page 79: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/79.jpg)
def insert(x: Int, t: BinTree): BinTree = { t match { case Empty() => ? case Node(left, value, right) => ?
} }
Insert in Binary Search Tree
![Page 80: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/80.jpg)
def insert(x: Int, t: BinTree): BinTree = { t match { case Empty() => Node(Empty(), x, Empty()) case Node(left, value, right) => if(x < value) Node(insert(x, left), value, right) else if(x > value) Node(left, value, insert(x, right)) else t } }
Insert in Binary Search Tree
![Page 81: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/81.jpg)
def toBinTree(xs: IntList): BinTree = xs match { case Nil() => Empty() case Cons(y, ys) => insert(y, toBinTree(ys))}
def listSort(xs: IntList): IntList = toList(toBinTree(xs))
Insert in Binary Search Tree
![Page 82: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/82.jpg)
Algebraic Datatypes in C
Based on: Simple algebraic data types for C by Pieter Hartel and Henk Muller. Version 8, 2nd September, 2010
![Page 83: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/83.jpg)
abstract class Treecase class Leaf(v: Int)case class Branch(v: Int, left: Tree, right: Tree)
def sum(t: Tree): Int = t match { case Leaf(v) => v case Branch(v, left, right) => v + sum(left) + sum(right)}
Algebraic Data Types in Scala
![Page 84: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/84.jpg)
typedef struct tree_struct { int val; struct tree_struct *left; struct tree_struct *right;} tree;
tree *mkBRANCH(int val, tree *left, tree *right) { tree *result = calloc(1, sizeof(struct tree_struct)); if (result == NULL) { printf("panic\n"); } result->val = val; result->left = left; result->right = right; return result;}
ADT K&R Style
![Page 85: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/85.jpg)
int krsum1(tree *cur) { if (cur == NULL) { return 0; } else { return cur->val + krsum1(cur->left) + krsum1(cur->right); }}int krsum2(tree_cc *cur) { /*assert cur->left==NULL <==> cur->right==NULL*/ if (cur->left == NULL) { return cur->val; } else { return cur->val + krsum1(cur->left) + krsum2(cur->right); }}void test() { tree *r = mkBRANCH(30, NULL, NULL); tree *l = mkBRANCH(20, NULL, NULL); tree *t = mkBRANCH(10, l, r); printf("%d\n", krsum1(t));}
ADT K&R Style
![Page 86: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/86.jpg)
No explicit cases for Leaf and Branch
• distinction by use of NULL values for branches
• Does not cater for more alternatives
Confusion about NULL
• uninitialized value
• end-of-list, leaf-of-tree
• => errors
Explicit allocation of tree nodes
ADT K&R Style
![Page 87: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/87.jpg)
typedef enum { LEAF = 0, BRANCH = 1} tree_tag;
typedef struct tree_struct { tree_tag tag; char *filename; union { struct { int _val; } _LEAF; struct { int _val; struct tree_struct *_left; struct tree_struct *_right; } _BRANCH; } data;} tree;
Algebraic Data Type with Union
![Page 88: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/88.jpg)
tree *mkLEAF(int _val) { tree *result = calloc(1, sizeof(struct tree_struct)); if (result == NULL) { printf("panic\n"); } result->tag = LEAF; result->data._LEAF._val = val; return result;}
tree *mkBRANCH(int val, tree *left, tree *right) { tree *result = calloc(1, sizeof(struct tree_struct)); if (result == NULL) { printf("panic\n"); } result->tag = BRANCH; result->data._BRANCH._val = val; result->data._BRANCH._left = left; result->data._BRANCH._right = right; return result;}
Algebraic Data Type with Union
![Page 89: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/89.jpg)
int sum(tree *t) { if (t == NULL) { return 0; } else if (t->tag == LEAF) { return t->data._LEAF._val; } else { // t->tag == BRANCH return t->data._BRANCH._val + sum(t->data._BRANCH._left) + sum(t->data._BRANCH._right); }}
Recursive Functions on ADT
![Page 90: Lecture 5: Functional Programming](https://reader033.vdocuments.us/reader033/viewer/2022052505/554e72feb4c905f66a8b4bee/html5/thumbnails/90.jpg)
Reading & Programming in Week 5
Reading
Sebesta Chapter 6:
Scala Chapter 6: Functional Objects
Scala Chapter 15: Case Classes and Pattern Matching
Week 6: First-Class Functions
WebLab: C, JavaScript, Scala tutorialsGraded Assignment 1: Dynamic Dispatch in C (deadline 2 April 2013, 23:59)