SlideShare ist ein Scribd-Unternehmen logo
1 von 90
Downloaden Sie, um offline zu lesen
Lecture 5: Functional Programming




                      TI1220 2012-2013
              Concepts of Programming Languages

                      Eelco Visser / TU Delft
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.



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.


http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
Outline
  From the lab:
     Unit testing
     Graded assignment 1
  Functional objects in Scala
  Pattern matching
  Recursion and induction
  Algebraic data types
  Binary trees
  Algebraic data types in C
Messages from the Lab
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
Unit Testing in Scala


            import org.scalatest.Suite

            class <NameOfTestClass> extends Suite {
              import <ClassUnderTest>._

                def <testNameOfTest> {
                  expect(<expected result>) {
                    <computation>
                  }
                }
            }
/* import test framework .h */
#include "solution.c"
#include "CuTest.h"
#include "CuJoin.h"
                                                 Unit Testing in C
/* 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("hellon 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);
}
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
Graded Assignment 1
  Algebraic datatypes in C
  Dynamic dispatch in C

Important dates
   Deadline: April 2, 2013 23:59
   Extension: April 5, 2013 23:59

   Submitting after extension date is not possible
   Maximum penalty for submitting after deadline: 6 points
   Minimum grade needed: 4
   Grade: 70% unit tests, 30% check lists
   Grade for GAs: average of four assignments
Algebraic Datatypes in C
abstract class XML
case class Text(t: String) extends XML
case 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)
      })

}




       translate this Scala program to an equivalent C program
// values

abstract class Value {
  def value: Int                                    Dynamic Dispatch in C
  def isFailure: Boolean
  def +(that: Value): Value
  def *(that: Value): Value
}

object LookupFailure extends Value {
  def value: Int = 0
                                                    translate this Scala program
  def isFailure: Boolean = true                     to an equivalent C program
  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
  }
}
// environments

abstract class Env {                               Dynamic Dispatch in C
  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);
}
// expressions

abstract class Exp {
  def eval(env: Env): Value;
                                                    Dynamic Dispatch in C
  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 + ")"
}
Functional Programming
       (in Scala)
Ingredients of functional programming

   Immutable objects

   Pattern matching

   Inductive (algebraic) data types

   Recursive functions

   First-class functions (next week)
Functional Objects in Scala
functional object: the fields
 of an object are immutable
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
Constructing a Rational


                                            class parameters


            class Rational(n: Int, d: Int) {
              println("Created " + n + "/" + d)
            }




             scala> new Rational(1, 2)
             Created 1/2
             res0: Rational = Rational@2d83e895
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
Overriding Methods




class Rational(n: Int, d: Int) {
  override def toString = n + "/" + d
}




   scala> val half = new
   Rational(1, 2)
   half: Rational = 1/2
Checking Pre-conditions




       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
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)
}




                        Adding Rationals Functionally
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)
 }



$ 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
Functional Fields


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)
}




scala> new Rational(1,2) add new Rational(2,3)
res0: Rational = 7/6
Non-functional Objects

      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)
Destructive Update          half: ImperativeRational = 1/2

                            scala> val twothirds = new ImperativeRational(2,3)
                            twothirds: ImperativeRational = 2/3

                            scala> half.add(twothirds)

                            scala> half
                            res1: ImperativeRational = 7/6
Self References



     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
Auxiliary Constructors



class Rational(n: Int, d: Int) {
  require(d != 0)
  val numer = n
  val denom = d
  def this(n: Int) = this(n, 1)
      // auxiliary constructor
  ...
}




      scala> new Rational(6)
      res1: Rational = 6/1
Private Fields and Methods



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)
}




        scala> new Rational(6,42)
        res1: Rational = 1/7
Using Functions as Infix Operators




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/6
     scala> new Rational(1,2) add new Rational(2,3)
     res0: Rational = 7/6
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/14
                                           Operator Identifiers
scala> val d = a.+(b.*(c))
d: Rational = 11/14
scala> val d = a * b + c
d: Rational = 16/21
scala> val d = (a.*(b)).+(c)
d: Rational = 16/21




Invoking Operators
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
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
                                                           Identifier Syntax
•   arbitrary string enclosed in back ticks (` . . . `).
Method Overloading


       def *(that: Rational): Rational =
         new Rational(numer * that.numer, denom * that.denom)

       def *(i: Int): Rational =
         new Rational(numer * i, denom)




scala> val c = new Rational(3,7)
c: Rational = 3/7
                                              In a method call, the
scala> c * 2
                                          compiler picks the version
res1: Rational = 6/7
                                           of an overloaded method
                                          that correctly matches the
                                            types of the arguments.
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
       ^
Implicit Conversions


def *(that: Rational): Rational =
  new Rational(numer * that.numer, denom * that.denom)

def *(i: Int): Rational =
  new Rational(numer * i, denom)




implicit def intToRational(x: Int) = new Rational(x)



                 scala> 2 * c
                 res4: Rational = 6/7
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
Pattern Matching
e0 match   {
  case 1   => e1;
  case 2   => e2;                  Scala’s Match
  case _   => e3
}




                    Match is similar to Java switch. Differences:

                    • Match is expression: returns a value
                    • Alternatives never fall through
                    • MatchError when no pattern matches
val firstArg = if (args.length > 0) args(0) else ""
firstArg match {
  case "salt" => println("pepper")
  case "chips" => println("salsa")
  case "eggs" => println("bacon")
                                       Choosing between Actions
  case _ => println("huh?")
}




val firstArg = if (!args.isEmpty) args(0) else ""
val friend =
  firstArg match {
    case "salt" => "pepper"
    case "chips" => "salsa"
    case "eggs" => "bacon"
    case _ => "huh?"                    Choosing between Values
  }
println(friend)
def describe(x: Any) = x match {
  case 5 => "five"
  case true => "truth"
  case "hello" => "hi!"                   Constant Patterns
  case Nil => "the empty list"
  case _ => "something else"
}




expr match {
  case 0 => "zero"
  case somethingElse => "not zero: " + somethingElse
}




                                           Pattern Variables
Recursion and Induction
Inductive Definitions




         Natural number

         • 0 is a number
         • if n is a number then n + 1 is a number
         • nothing else is a natural number
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
def isEven(n: Int): Boolean =
  n match {
    case 0 => ?
    case m => ?
  }

def isOdd(n: Int): Boolean =
  n match {
    case 0 => ?
    case m => ?
  }
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)
  }
def power(n: Int, exp: Int): Int =
  exp match {
    case 0 => ?
    case m =>
      ?




  }
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)
  }
Algebraic Data Types
Inductive Data Structures



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




Nil()
Cons(1, Nil())                          Scala: Case Classes
Cons(2, Cons(1, Nil()))
Cons(1, Cons(2, Cons(3, Nil())))
...
abstract class IntList
case class Nil() extends IntList
case 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
length of list xs




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




def length(xs: IntList): Int =
  xs match {
    case Nil() => 0
    case Cons(x, ys) => 1 + length(ys)
  }
sum of the integers in xs



             def sum(xs: IntList): Int =
               xs match {
                 case Nil() => ?
                 case Cons(x, ys) => ?
               }
sum of the integers in xs



             def sum(xs: IntList): Int =
               xs match {
                 case Nil() => 0
                 case Cons(x, ys) => x + sum(ys)
               }
def product(xs: IntList): Int =
  xs match {
    case Nil() => ?
    case Cons(x, ys) => ?
  }




           product of the integers in xs
def product(xs: IntList): Int =
  xs match {
    case Nil() => 1
    case Cons(x, ys) => x * product(ys)
  }




           product of the integers in xs
def append(xs: IntList, ys: IntList): IntList =
  xs match {
    case Nil() => ?
    case Cons(x, zs) => ?
  }




         append elements of ys to xs
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
elements of xs in reverse




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




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




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
the list of elements of xs that are even



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)
    }
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
def msort(xs: IntList): IntList = {                Merge Sort
  val n = lenght(xs) / 2
  n match {
    case 0 => xs
    case _ => val (as, bs) = splitAt(xs, n)
              merge(msort(as), msort(bs))
  }
}



        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)
            }
          }
Merge Sort


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))
      }
  }
abstract class IntList
case class Nil() extends IntList
case 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
Binary Trees
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()))
def f(t: BinTree): A =
  t match {                          Node(Node(Empty(), 2, Empty()),
                                          5, Node(Empty(), 42, Empty()))
    case Empty() => ...
    case Node(t1, i, t2) =>
      ... f(t1) ... f(t2) ...
  }
def replace(x: Int, y: Int, t: BinTree): BinTree =
  t match {
    case Empty() => ?
    case Node(l, n, r) =>
      ?




  }




                            replace occurrence of x by y
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
def toList(t: BinTree): IntList = t match {
  case Empty() => ?
  case Node(l, n, r) =>
    ?
}




                         transform binary tree to list
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
Binary Search Trees



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): BinTree
def lookup(x: Int, t: BinTree): Boolean


Correctness
lookup(x, insert(x, t)) == true
Lookup in Binary
                            Search Tree




def lookup(x: Int, t: BinTree): Boolean = {
  t match {
    case Empty() => ?
    case Node(left, value, right) =>
      ?




      }
  }
Lookup in Binary
                            Search Tree




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
    }
  }
Insert in Binary
    Search Tree




def insert(x: Int, t: BinTree): BinTree = {
  t match {
    case Empty() => ?
    case Node(left, value, right) =>
     ?




      }
  }
Insert in Binary
    Search Tree




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



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))
Algebraic Datatypes in C



    Based on: Simple algebraic data types for C by Pieter
    Hartel and Henk Muller. Version 8, 2nd September, 2010
Algebraic Data Types in Scala




abstract class Tree
case 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)
}
ADT K&R Style



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("panicn");
	 }
	 result->val = val;
	 result->left = left;
	 result->right = right;
	 return result;
}
int krsum1(tree *cur) {                         ADT K&R Style
	 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("%dn", krsum1(t));
}
ADT K&R Style



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
Algebraic Data Type with Union


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

tree *mkLEAF(int _val) {
	 tree *result = calloc(1, sizeof(struct tree_struct));
	 if (result == NULL) {
	 	 printf("panicn");
	 }
	 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("panicn");
	 }
	 result->tag = BRANCH;
	 result->data._BRANCH._val = val;
	 result->data._BRANCH._left = left;
	 result->data._BRANCH._right = right;
	 return result;
}
Recursive Functions on ADT




            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);
            	 }
            }
Reading & Programming in Week 5

Reading

  Sebesta Chapter 6:

  Scala Chapter 6: Functional Objects

  Scala Chapter 15: Case Classes and Pattern Matching

WebLab:
  C, JavaScript, Scala tutorials
   Graded Assignment 1: Dynamic Dispatch in C
   (deadline 2 April 2013, 23:59)


                                   Week 6: First-Class Functions

Weitere ähnliche Inhalte

Was ist angesagt?

Demystifying functional programming with Scala
Demystifying functional programming with ScalaDemystifying functional programming with Scala
Demystifying functional programming with ScalaDenis
 
Python Programming - IX. On Randomness
Python Programming - IX. On RandomnessPython Programming - IX. On Randomness
Python Programming - IX. On RandomnessRanel Padon
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheoryKnoldus Inc.
 
Programming in Scala - Lecture Four
Programming in Scala - Lecture FourProgramming in Scala - Lecture Four
Programming in Scala - Lecture FourAngelo Corsaro
 
Data Structure Project File
Data Structure Project FileData Structure Project File
Data Structure Project FileDeyvessh kumar
 
Data structure lab manual
Data structure lab manualData structure lab manual
Data structure lab manualnikshaikh786
 
Templates in C++
Templates in C++Templates in C++
Templates in C++Tech_MX
 
Object Equality in Scala
Object Equality in ScalaObject Equality in Scala
Object Equality in ScalaKnoldus Inc.
 
Java8: Language Enhancements
Java8: Language EnhancementsJava8: Language Enhancements
Java8: Language EnhancementsYuriy Bondaruk
 
Programming in Scala - Lecture Two
Programming in Scala - Lecture TwoProgramming in Scala - Lecture Two
Programming in Scala - Lecture TwoAngelo Corsaro
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in ScalaKnoldus Inc.
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondMario Fusco
 

Was ist angesagt? (20)

Demystifying functional programming with Scala
Demystifying functional programming with ScalaDemystifying functional programming with Scala
Demystifying functional programming with Scala
 
Python Programming - IX. On Randomness
Python Programming - IX. On RandomnessPython Programming - IX. On Randomness
Python Programming - IX. On Randomness
 
Clojure basics
Clojure basicsClojure basics
Clojure basics
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheory
 
Programming in Scala - Lecture Four
Programming in Scala - Lecture FourProgramming in Scala - Lecture Four
Programming in Scala - Lecture Four
 
Scala collection
Scala collectionScala collection
Scala collection
 
Lec3
Lec3Lec3
Lec3
 
Scala functions
Scala functionsScala functions
Scala functions
 
Ti1220 Lecture 2
Ti1220 Lecture 2Ti1220 Lecture 2
Ti1220 Lecture 2
 
Data Structure Project File
Data Structure Project FileData Structure Project File
Data Structure Project File
 
Meet scala
Meet scalaMeet scala
Meet scala
 
Suit case class
Suit case classSuit case class
Suit case class
 
Data structure lab manual
Data structure lab manualData structure lab manual
Data structure lab manual
 
Templates in C++
Templates in C++Templates in C++
Templates in C++
 
Knolx session
Knolx sessionKnolx session
Knolx session
 
Object Equality in Scala
Object Equality in ScalaObject Equality in Scala
Object Equality in Scala
 
Java8: Language Enhancements
Java8: Language EnhancementsJava8: Language Enhancements
Java8: Language Enhancements
 
Programming in Scala - Lecture Two
Programming in Scala - Lecture TwoProgramming in Scala - Lecture Two
Programming in Scala - Lecture Two
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in Scala
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 

Ähnlich wie Here are the key points about functional programming in Scala covered in the document:- Immutable objects - fields of functional objects are immutable- Pattern matching - Inductive (algebraic) data types- Recursive functions- First-class functions (mentioned but not covered)Some examples covered:- Rational number class with immutable fields and functional methods like add- Checking pre-conditions with require- Overriding toString- Auxiliary constructors- Private fields and methods- Self references with this- Using functions as infix operatorsThe document provides examples of functional programming concepts in Scala like immutable data structures, pattern matching, recursion, and functional methods. It compares

Principles of functional progrmming in scala
Principles of functional progrmming in scalaPrinciples of functional progrmming in scala
Principles of functional progrmming in scalaehsoon
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming iiPrashant Kalkar
 
Introduction à Scala - Michel Schinz - January 2010
Introduction à Scala - Michel Schinz - January 2010Introduction à Scala - Michel Schinz - January 2010
Introduction à Scala - Michel Schinz - January 2010JUG Lausanne
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with ScalaNeelkanth Sachdeva
 
TI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type ParameterizationTI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type ParameterizationEelco Visser
 
The Scala Programming Language
The Scala Programming LanguageThe Scala Programming Language
The Scala Programming Languageleague
 
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Data Con LA
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?Tomasz Wrobel
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesTomer Gabel
 

Ähnlich wie Here are the key points about functional programming in Scala covered in the document:- Immutable objects - fields of functional objects are immutable- Pattern matching - Inductive (algebraic) data types- Recursive functions- First-class functions (mentioned but not covered)Some examples covered:- Rational number class with immutable fields and functional methods like add- Checking pre-conditions with require- Overriding toString- Auxiliary constructors- Private fields and methods- Self references with this- Using functions as infix operatorsThe document provides examples of functional programming concepts in Scala like immutable data structures, pattern matching, recursion, and functional methods. It compares (20)

Functional object
Functional objectFunctional object
Functional object
 
Principles of functional progrmming in scala
Principles of functional progrmming in scalaPrinciples of functional progrmming in scala
Principles of functional progrmming in scala
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
 
Scala
ScalaScala
Scala
 
Introduction à Scala - Michel Schinz - January 2010
Introduction à Scala - Michel Schinz - January 2010Introduction à Scala - Michel Schinz - January 2010
Introduction à Scala - Michel Schinz - January 2010
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with Scala
 
TI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type ParameterizationTI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type Parameterization
 
Introducing scala
Introducing scalaIntroducing scala
Introducing scala
 
Scala for curious
Scala for curiousScala for curious
Scala for curious
 
Scala Bootcamp 1
Scala Bootcamp 1Scala Bootcamp 1
Scala Bootcamp 1
 
The Scala Programming Language
The Scala Programming LanguageThe Scala Programming Language
The Scala Programming Language
 
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
 
Python : Functions
Python : FunctionsPython : Functions
Python : Functions
 
Jeop game-final-review
Jeop game-final-reviewJeop game-final-review
Jeop game-final-review
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
 
Lecture 3
Lecture 3Lecture 3
Lecture 3
 

Mehr von Eelco Visser

CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term RewritingCS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term RewritingEelco Visser
 
CS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesCS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesEelco Visser
 
CS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingCS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingEelco Visser
 
CS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definitionCS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definitionEelco Visser
 
CS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: IntroductionCS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: IntroductionEelco Visser
 
A Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation RulesA Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation RulesEelco Visser
 
Declarative Type System Specification with Statix
Declarative Type System Specification with StatixDeclarative Type System Specification with Statix
Declarative Type System Specification with StatixEelco Visser
 
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler ConstructionCompiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler ConstructionEelco Visser
 
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)Eelco Visser
 
Compiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory ManagementCompiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory ManagementEelco Visser
 
Compiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | InterpretersCompiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | InterpretersEelco Visser
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationEelco Visser
 
Compiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual MachinesCompiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual MachinesEelco Visser
 
Compiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone FrameworksCompiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone FrameworksEelco Visser
 
Compiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow AnalysisCompiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow AnalysisEelco Visser
 
Compiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionCompiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionEelco Visser
 
Compiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type ConstraintsCompiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type ConstraintsEelco Visser
 
Compiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type CheckingCompiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type CheckingEelco Visser
 
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static AnalysisCompiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static AnalysisEelco Visser
 
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term RewritingCompiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term RewritingEelco Visser
 

Mehr von Eelco Visser (20)

CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term RewritingCS4200 2019 | Lecture 5 | Transformation by Term Rewriting
CS4200 2019 | Lecture 5 | Transformation by Term Rewriting
 
CS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesCS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic Services
 
CS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingCS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | Parsing
 
CS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definitionCS4200 2019 | Lecture 2 | syntax-definition
CS4200 2019 | Lecture 2 | syntax-definition
 
CS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: IntroductionCS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: Introduction
 
A Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation RulesA Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation Rules
 
Declarative Type System Specification with Statix
Declarative Type System Specification with StatixDeclarative Type System Specification with Statix
Declarative Type System Specification with Statix
 
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler ConstructionCompiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler Construction
 
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
 
Compiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory ManagementCompiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory Management
 
Compiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | InterpretersCompiler Construction | Lecture 14 | Interpreters
Compiler Construction | Lecture 14 | Interpreters
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code Generation
 
Compiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual MachinesCompiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual Machines
 
Compiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone FrameworksCompiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone Frameworks
 
Compiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow AnalysisCompiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow Analysis
 
Compiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionCompiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint Resolution
 
Compiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type ConstraintsCompiler Construction | Lecture 8 | Type Constraints
Compiler Construction | Lecture 8 | Type Constraints
 
Compiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type CheckingCompiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type Checking
 
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static AnalysisCompiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static Analysis
 
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term RewritingCompiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
 

Here are the key points about functional programming in Scala covered in the document:- Immutable objects - fields of functional objects are immutable- Pattern matching - Inductive (algebraic) data types- Recursive functions- First-class functions (mentioned but not covered)Some examples covered:- Rational number class with immutable fields and functional methods like add- Checking pre-conditions with require- Overriding toString- Auxiliary constructors- Private fields and methods- Self references with this- Using functions as infix operatorsThe document provides examples of functional programming concepts in Scala like immutable data structures, pattern matching, recursion, and functional methods. It compares

  • 1. Lecture 5: Functional Programming TI1220 2012-2013 Concepts of Programming Languages Eelco Visser / TU Delft
  • 2.
  • 3. 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. 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. http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
  • 4. Outline From the lab: Unit testing Graded assignment 1 Functional objects in Scala Pattern matching Recursion and induction Algebraic data types Binary trees Algebraic data types in C
  • 6. 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
  • 7. Unit Testing in Scala import org.scalatest.Suite class <NameOfTestClass> extends Suite { import <ClassUnderTest>._ def <testNameOfTest> { expect(<expected result>) { <computation> } } }
  • 8. /* import test framework .h */ #include "solution.c" #include "CuTest.h" #include "CuJoin.h" Unit Testing in C /* 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("hellon 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); }
  • 9. 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
  • 10. Graded Assignment 1 Algebraic datatypes in C Dynamic dispatch in C Important dates Deadline: April 2, 2013 23:59 Extension: April 5, 2013 23:59 Submitting after extension date is not possible Maximum penalty for submitting after deadline: 6 points Minimum grade needed: 4 Grade: 70% unit tests, 30% check lists Grade for GAs: average of four assignments
  • 11. Algebraic Datatypes in C abstract class XML case class Text(t: String) extends XML case 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) }) } translate this Scala program to an equivalent C program
  • 12. // values abstract class Value { def value: Int Dynamic Dispatch in C def isFailure: Boolean def +(that: Value): Value def *(that: Value): Value } object LookupFailure extends Value { def value: Int = 0 translate this Scala program def isFailure: Boolean = true to an equivalent C program 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 } }
  • 13. // environments abstract class Env { Dynamic Dispatch in C 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); }
  • 14. // expressions abstract class Exp { def eval(env: Env): Value; Dynamic Dispatch in C 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 + ")" }
  • 16. Ingredients of functional programming Immutable objects Pattern matching Inductive (algebraic) data types Recursive functions First-class functions (next week)
  • 18. functional object: the fields of an object are immutable
  • 19. 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
  • 20. Constructing a Rational class parameters class Rational(n: Int, d: Int) { println("Created " + n + "/" + d) } scala> new Rational(1, 2) Created 1/2 res0: Rational = Rational@2d83e895
  • 21. 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
  • 22. Overriding Methods class Rational(n: Int, d: Int) { override def toString = n + "/" + d } scala> val half = new Rational(1, 2) half: Rational = 1/2
  • 23. Checking Pre-conditions 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
  • 24. 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) } Adding Rationals Functionally
  • 25. 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) } $ 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
  • 26. Functional Fields 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) } scala> new Rational(1,2) add new Rational(2,3) res0: Rational = 7/6
  • 27. Non-functional Objects 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) Destructive Update half: ImperativeRational = 1/2 scala> val twothirds = new ImperativeRational(2,3) twothirds: ImperativeRational = 2/3 scala> half.add(twothirds) scala> half res1: ImperativeRational = 7/6
  • 28. Self References 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
  • 29. Auxiliary Constructors class Rational(n: Int, d: Int) { require(d != 0) val numer = n val denom = d def this(n: Int) = this(n, 1) // auxiliary constructor ... } scala> new Rational(6) res1: Rational = 6/1
  • 30. Private Fields and Methods 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) } scala> new Rational(6,42) res1: Rational = 1/7
  • 31. Using Functions as Infix Operators 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/6 scala> new Rational(1,2) add new Rational(2,3) res0: Rational = 7/6
  • 32. 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/14 Operator Identifiers scala> val d = a.+(b.*(c)) d: Rational = 11/14 scala> val d = a * b + c d: Rational = 16/21 scala> val d = (a.*(b)).+(c) d: Rational = 16/21 Invoking Operators
  • 33. 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
  • 34. 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 Identifier Syntax • arbitrary string enclosed in back ticks (` . . . `).
  • 35. Method Overloading def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom) def *(i: Int): Rational = new Rational(numer * i, denom) scala> val c = new Rational(3,7) c: Rational = 3/7 In a method call, the scala> c * 2 compiler picks the version res1: Rational = 6/7 of an overloaded method that correctly matches the types of the arguments.
  • 36. 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 ^
  • 37. Implicit Conversions def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom) def *(i: Int): Rational = new Rational(numer * i, denom) implicit def intToRational(x: Int) = new Rational(x) scala> 2 * c res4: Rational = 6/7
  • 38. 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
  • 40. e0 match { case 1 => e1; case 2 => e2; Scala’s Match case _ => e3 } Match is similar to Java switch. Differences: • Match is expression: returns a value • Alternatives never fall through • MatchError when no pattern matches
  • 41. val firstArg = if (args.length > 0) args(0) else "" firstArg match { case "salt" => println("pepper") case "chips" => println("salsa") case "eggs" => println("bacon") Choosing between Actions case _ => println("huh?") } val firstArg = if (!args.isEmpty) args(0) else "" val friend = firstArg match { case "salt" => "pepper" case "chips" => "salsa" case "eggs" => "bacon" case _ => "huh?" Choosing between Values } println(friend)
  • 42. def describe(x: Any) = x match { case 5 => "five" case true => "truth" case "hello" => "hi!" Constant Patterns case Nil => "the empty list" case _ => "something else" } expr match { case 0 => "zero" case somethingElse => "not zero: " + somethingElse } Pattern Variables
  • 44. Inductive Definitions Natural number • 0 is a number • if n is a number then n + 1 is a number • nothing else is a natural number
  • 45. 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
  • 46. def isEven(n: Int): Boolean = n match { case 0 => ? case m => ? } def isOdd(n: Int): Boolean = n match { case 0 => ? case m => ? }
  • 47. 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) }
  • 48. def power(n: Int, exp: Int): Int = exp match { case 0 => ? case m => ? }
  • 49. 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) }
  • 51. Inductive Data Structures 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
  • 52. 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 Nil() Cons(1, Nil()) Scala: Case Classes Cons(2, Cons(1, Nil())) Cons(1, Cons(2, Cons(3, Nil()))) ...
  • 53. abstract class IntList case class Nil() extends IntList case 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
  • 54. length of list xs def length(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }
  • 55. length of list xs def length(xs: IntList): Int = xs match { case Nil() => 0 case Cons(x, ys) => 1 + length(ys) }
  • 56. sum of the integers in xs def sum(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? }
  • 57. sum of the integers in xs def sum(xs: IntList): Int = xs match { case Nil() => 0 case Cons(x, ys) => x + sum(ys) }
  • 58. def product(xs: IntList): Int = xs match { case Nil() => ? case Cons(x, ys) => ? } product of the integers in xs
  • 59. def product(xs: IntList): Int = xs match { case Nil() => 1 case Cons(x, ys) => x * product(ys) } product of the integers in xs
  • 60. def append(xs: IntList, ys: IntList): IntList = xs match { case Nil() => ? case Cons(x, zs) => ? } append elements of ys to xs
  • 61. 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
  • 62. elements of xs in reverse def reverse(xs: IntList): IntList = xs match { case Nil() => ? case Cons(y, ys) => ? }
  • 63. elements of xs in reverse def reverse(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => append(reverse(ys), Cons(y, Nil())) }
  • 64. def reverse(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => append(reverse(ys), Cons(y, Nil())) } 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
  • 65. the list of elements of xs that are even 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) }
  • 66. 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
  • 67. def msort(xs: IntList): IntList = { Merge Sort val n = lenght(xs) / 2 n match { case 0 => xs case _ => val (as, bs) = splitAt(xs, n) merge(msort(as), msort(bs)) } } 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) } }
  • 68. Merge Sort 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)) } }
  • 69. abstract class IntList case class Nil() extends IntList case 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
  • 71. 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())) def f(t: BinTree): A = t match { Node(Node(Empty(), 2, Empty()), 5, Node(Empty(), 42, Empty())) case Empty() => ... case Node(t1, i, t2) => ... f(t1) ... f(t2) ... }
  • 72. def replace(x: Int, y: Int, t: BinTree): BinTree = t match { case Empty() => ? case Node(l, n, r) => ? } replace occurrence of x by y
  • 73. 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
  • 74. def toList(t: BinTree): IntList = t match { case Empty() => ? case Node(l, n, r) => ? } transform binary tree to list
  • 75. 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
  • 76. Binary Search Trees 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): BinTree def lookup(x: Int, t: BinTree): Boolean Correctness lookup(x, insert(x, t)) == true
  • 77. Lookup in Binary Search Tree def lookup(x: Int, t: BinTree): Boolean = { t match { case Empty() => ? case Node(left, value, right) => ? } }
  • 78. Lookup in Binary Search Tree 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 } }
  • 79. Insert in Binary Search Tree def insert(x: Int, t: BinTree): BinTree = { t match { case Empty() => ? case Node(left, value, right) => ? } }
  • 80. Insert in Binary Search Tree 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 } }
  • 81. Insert in Binary Search Tree 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))
  • 82. Algebraic Datatypes in C Based on: Simple algebraic data types for C by Pieter Hartel and Henk Muller. Version 8, 2nd September, 2010
  • 83. Algebraic Data Types in Scala abstract class Tree case 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) }
  • 84. ADT K&R Style 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("panicn"); } result->val = val; result->left = left; result->right = right; return result; }
  • 85. int krsum1(tree *cur) { ADT K&R Style 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("%dn", krsum1(t)); }
  • 86. ADT K&R Style 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
  • 87. Algebraic Data Type with Union 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;
  • 88. Algebraic Data Type with Union tree *mkLEAF(int _val) { tree *result = calloc(1, sizeof(struct tree_struct)); if (result == NULL) { printf("panicn"); } 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("panicn"); } result->tag = BRANCH; result->data._BRANCH._val = val; result->data._BRANCH._left = left; result->data._BRANCH._right = right; return result; }
  • 89. Recursive Functions on ADT 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); } }
  • 90. Reading & Programming in Week 5 Reading Sebesta Chapter 6: Scala Chapter 6: Functional Objects Scala Chapter 15: Case Classes and Pattern Matching WebLab: C, JavaScript, Scala tutorials Graded Assignment 1: Dynamic Dispatch in C (deadline 2 April 2013, 23:59) Week 6: First-Class Functions