- Concepts of Programming Languages

Methods and Functions: Currying

Instructor:

Learning Objectives

How are methods in object-oriented programming and functions in functional programming related?

  • Identify and describe the difference between methods and functions in Scala
  • Identify and describe the difference between tupled and curried definitions
  • Identify and use partial function application

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.
  • Functions foreach, map, filter are higher-order functions
    • they take a function as argument
    • Also common: return a function as the result

Paired Methods

  1. def add(x:Int, y:Int) = x+y
  2. add(11, 21)
  1. add: (x: Int, y: Int)Int
  2. res: Int = 32
  • This is the usual style of methods that take multiple arguments
  • It is a method that
    • Takes a pair of Ints
    • Returns an Int

Functions

  • Scala has first-class support for both functions and methods

Method

  1. def add(x:Int, y:Int) = x+y
  2. add(1,2)
  • Part of a class structure
  • Can be overridden
  • Has access to fields

Function

  1. val add = (x:Int, y:Int) => x+y
  2. add(1,2)
  • Can be passed as arguments, returned, assigned to variables

Function Notation

  • Using lambda notation
    1. val add = (x:Int, y:Int) => x+y
    2. add(11,21)
  • Use underscore when parameters used exactly once
    1. val add = (_:Int) + (_:Int)
    2. add(11,21)
  • Types may be inferred in some contexts
    1. var add : (Int,Int)=>Int = _ + _
    2. add(11,21)

Curried Functions

  1. val add = (x:Int) => (y:Int) => x+y
  2. add(11)(21)
  1. add: Int => (Int => Int) = $$Lambda$...
  2. res: Int = 32
  • This is a curried definition
  • It is a function that
    • Takes an Int
    • Returns a function of type Int=>Int

Curried Methods

  1. def add(x:Int) = (y:Int) => x+y
  2. add(11)(21)
  1. add: (x: Int)Int => Int
  2. res: Int = 32
  • You can mix the notations
  • This is a method that
    • Takes an Int
    • Returns a function of type Int=>Int

Converting Methods to Functions

  1. def add(x:Int, y:Int) = x+y
  2. val addf = add _
  1. add: (x: Int, y: Int)Int
  2. addf: (Int, Int) => Int = $$Lambda$...
  • Another use of wildcard operator _
    • don't care pattern
    • anonymous function expression

Partial Application

  1. val addf = (x:Int) => (y:Int) => x+y
  2. def addm(x:Int) = (y:Int) => x+y
  3. val addfp = addf(11)
  4. val addmp = addm(11)
  5. val rf = addfp(21)
  6. val rm = addmp(21)
  1. addf: Int => (Int => Int) = $$Lambda$
  2. addm: (x: Int)Int => Int
  3. addfp: Int => Int = $$Lambda$
  4. addmp: Int => Int = $$Lambda$
  5. rf: Int = 32
  6. rp: Int = 32

Functions as Objects

  1. def a (x:Int) = x + 1
  2. val b = (x:Int) => x + 1
  3. //[Arg,Result]
  4. val c = new Function[Int,Int] {
  5. def apply(x:Int) = x + 1
  6. }
  7. //[Argument, Result]
  8. val d : PartialFunction[Matchable, Int] = {
  9. case i: Int => i + 1
  10. }
  11. val fs = List(a,b,c,d)
  12. for f <- fs yield f(4)
  1. fs: List[Int => Int] = List($$Lambda$, $$Lambda$, <function1>, <function1>)
  2. res1: List[Int] = List(5, 5, 5, 5)
  • What's going on here?

Functions and Methods

  • def defines a method with explicit parameter types
  • => defines a function with inferable parameter types
  • Functions are objects with method apply
    • Function e:X=>Y gets compiled to an object
      1. val e = new Function[X,Y] {
      2. def apply(x:X) : Y = ...
      3. }
    • Function application e(args) is method invocation e.apply(args)

Summary

  • Tupled definitions: functions with multiple arguments
  • Curried definitions: a family of single-argument functions
  • In Scala, functions are objects with an apply method
  • Partial application creates new functions

Partial Application

  1. def add1(x:Int, y:Int) = x+y
  2. def add2(x:Int)(y:Int) = x+y
  3. val add3 = (x:Int, y:Int) => x+y
  4. val add4 = (x:Int) => (y:Int) => x+y
  5. def add5(x:Int) = (y:Int) => x+y
  6. val add1p = add1(11, _) /* x=>add1(11, x) */
  7. val add2p = add2(11)(_) /* x=>add2(11)(x) */
  8. val add3p = add3(11, _) /* x=>add3(11, x) */
  9. val add4p = add4(11)
  10. val add5p = add5(11)
  11. for f <- List(add1p, add2p, add3p, add4p, add5p)
  12. yield f(21)
  1. fs: List[Int => Int] = List($$Lambda$,$$Lambda$,$$Lambda$,$$Lambda$,$$Lambda$)
  2. res1: List[Int] = List(32, 32, 32, 32, 32)

# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-robot fa-stack-1x fa-inverse"></i></span> Example - :fa fa-terminal: In Scala 3, implement a function to add two integer numbers. * :fa fa-comment-dots: ```scala def add(a: Int, b: Int): Int = { a + b } ``` * :fa fa-bolt-lightning: [Is this really a function or rather a method?](https://docs.scala-lang.org/tour/basics.html#methods) ---

# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Curried Methods <div class="grid grid-cols-2 gap-4"> <div> ```scala def add(x:Int)(y:Int) = x+y add(11)(21) ``` </div> <div> ```scala add: (x: Int)(y: Int)Int res: Int = 32 ``` </div> </div> - This is a [curried](https://en.wikipedia.org/wiki/Currying) definition - It is a _method_ that - Takes an Int - Returns a method of type `(y:Int)Int` - So together the type of the method is `add2: (x:Int)(y:Int)Int` ---

# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Functions <div class="grid grid-cols-2 gap-4"> <div> ```scala val add = (x:Int, y:Int) => x+y add(11, 21) ``` </div> <div> ```scala add: (Int, Int) => Int = $$Lambda$4576/0x00000008018d1840@6ae4d2ad res: Int = 32 ``` </div> </div> - This is a _function_ that - Takes a pair of `Int`s - Returns an `Int` ---