CSC447

Concepts of Programming Languages

Methods and Functions

Instructor: James Riely

Video

Open on youtube

Functional Programming

  • We say that functions are first-class if they can be
    • declared within any scope,
    • passed as arguments to other functions, and
    • returned as results of functions.
  • foreach, map, filter are higher-order functions
    • they take a function as argument
  • Also common: return a function as the result

Paired Method


def add1(x:Int, y:Int) = x+y
add1(11, 21)
          

add1: (x: Int, y: Int)Int
res1: Int = 32
          
  • This is normal definition
  • It is a method that
    • Takes a pair of Ints
    • Returns an Int

Curried Method


def add2(x:Int)(y:Int) = x+y
add2(11)(21)
          

add2: (x: Int)(y: Int)Int
res2: Int = 32
          
  • This is a curried definition
  • It is a method that
    • Takes an Int
    • Returns a function of type (y: Int)Int

Paired Function


val add3 = (x:Int, y:Int) => x+y
add3(11, 21)
          

add3: (Int, Int) => Int = $$Lambda$4576/0x00000008018d1840@6ae4d2ad
res3: Int = 32
          
  • Scala has first-class for both functions and object
  • This is a function that
    • Takes a pair of Ints
    • Returns an Int

Curried Function


val add4 = (x:Int) => (y:Int) => x+y
add4(11)(21)
          

add4: Int => (Int => Int) = $$Lambda$...
res4: Int = 32
          
  • This is a curried definition
  • It is a function that
    • Takes an Int
    • Returns a function of type Int=>Int

Curried Method


def add5(x:Int) = (y:Int) => x+y
add5(11)(21)
          

add5: (x: Int)Int => Int
res5: Int = 32
          
  • You can mix the notations
  • This compiles the same as add2
    • Takes an Int
    • Returns a function of type Int=>Int

Curried Method


def add2(x:Int)(y:Int) = x+y
add2(11)(21)
          

add2: (x: Int)(y: Int)Int
res2: Int = 32
          
  • This is a curried definition
  • It is a method that
    • Takes an Int
    • Returns a function of type (y: Int)Int

Method to Function


def add1(x:Int, y:Int) = x+y
def add2(x:Int)(y:Int) = x+y
val add1f = add1
val add2f = add2
          

add1: (x: Int, y: Int)Int
add2: (x: Int)(y: Int)Int
add1f: (Int, Int) => Int = $$Lambda$...
add2f: Int => (Int => Int) = $$Lambda$...
          

Partial application


val add4 = (x:Int) => (y:Int) => x+y
def add5(x:Int) = (y:Int) => x+y

val add4p = add4(11)
val add5p = add5(11)

val r4 = add4p(21)
val r5 = add5p(21)
          

add4: Int => (Int => Int) = $$Lambda$
add5: (x: Int)Int => Int

add4p: Int => Int = $$Lambda$
add5p: Int => Int = $$Lambda$

r4: Int = 32
r5: Int = 32
          

Partial application


def add1(x:Int, y:Int) = x+y
def add2(x:Int)(y:Int) = x+y
val add3 = (x:Int, y:Int) => x+y
val add4 = (x:Int) => (y:Int) => x+y
def add5(x:Int) = (y:Int) => x+y

val add1p = add1(11, _)  /* x=>add1(11, x) */
val add2p = add2(11)(_)  /* x=>add2(11)(x) */
val add3p = add3(11, _)  /* x=>add3(11, x) */
val add4p = add4(11)
val add5p = add5(11)
val fs = List(add1p, add2p, add3p, add4p, add5p)
for f <- fs yield f(21)
          

fs: List[Int => Int] = List($$Lambda$,$$Lambda$,$$Lambda$,$$Lambda$,$$Lambda$)
res1: List[Int] = List(32, 32, 32, 32, 32)
          

Builtin Folds are Curried

  • Note that foldLeft is curried
    
    xss.foldLeft (z) (f)
                  
    rather than
    
    xss.foldLeft (z, f)
                    

Functions and methods in Scala


def a (x:Int) = x + 1;
val b = (x:Int) => x + 1;
val c = new Function[Int,Int] { def apply(x:Int) = x + 1 }
val d : PartialFunction[Int, Int]  = { case i: Int => i + 1 }

val fs = List(a,b,c,d)
for f <- fs yield f(4)
          

fs: List[Int => Int] = List($$Lambda$, $$Lambda$, <function1>, <function1>)
res1: List[Int] = List(5, 5, 5, 5)
          

Functions and methods in Scala

  • def defines a method
    • parameters types explicit
  • => defines a function
    • parameter types inferable
  • Functions are objects with method apply
    • If e:X=>Y
    • Then e(args) === e.apply(args)