90
TI1220 2012-2013 Concepts of Programming Languages Eelco Visser / TU Delft Lecture 5: Functional Programming

Lecture 5: Functional Programming

Embed Size (px)

Citation preview

Page 1: Lecture 5: Functional Programming

TI1220 2012-2013Concepts of Programming Languages

Eelco Visser / TU Delft

Lecture 5: Functional Programming

Page 2: Lecture 5: Functional Programming
Page 3: Lecture 5: Functional Programming

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

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

Messages from the Lab

Page 6: Lecture 5: Functional Programming

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

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

/* 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

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

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

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

// 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

// 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

// 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

Functional Programming (in Scala)

Page 16: Lecture 5: Functional Programming

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

Functional Objects in Scala

Page 18: Lecture 5: Functional Programming

functional object: the fields of an object are immutable

Page 19: Lecture 5: Functional Programming

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

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

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

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

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

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

$ 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

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

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

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

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

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

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

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

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

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

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

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

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

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

Pattern Matching

Page 40: Lecture 5: Functional Programming

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

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

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

Recursion and Induction

Page 44: Lecture 5: Functional Programming

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

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

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

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

def power(n: Int, exp: Int): Int = exp match { case 0 => ? case m => ?

}

Page 49: Lecture 5: Functional Programming

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

Algebraic Data Types

Page 51: Lecture 5: Functional Programming

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

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

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

def length(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }

length of list xs

Page 55: Lecture 5: Functional Programming

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

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

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

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

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

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

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

def reverse(xs: IntList): IntList = xs match { case Nil() => ? case Cons(y, ys) => ? }

elements of xs in reverse

Page 63: Lecture 5: Functional Programming

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

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

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

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

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

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

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

Binary Trees

Page 71: Lecture 5: Functional Programming

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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)