KoreanFoodie's Study

Scala 5 - Currying 본문

Tutorials/Scala

Scala 5 - Currying

GoldGiver 2019. 4. 23. 19:00

스칼라 튜토리얼, scala에서 currying에 대해 알아보자


Currying

Why we use currying? Let's look at the code, simplified by currying.

def sum(f: Int=>Int, a: Int, b: Int): Int = 
if (a <= b) f(a) + sum(f, a+1, b) else 0
def linear(n: Int) = n
def square(n: Int) = n * n
def cube(n: Int) = n * n * n
def sumLinear(a: Int, b: Int) = sum(linear, a, b)
def sumSquare(a: Int, b: Int) = sum(square, a, b)
def sumCubes(a: Int, b: Int) = sum(cube, a, b)

We want the following. How?

def sumLinear = sum(linear)
def sumSquare = sum(square)
def sumCubes = sum(cube)
  • Solution :
def sum(f: Int => Int): (Int, Int) => Int = {
  def sumF(a: Int, b: Int): Int =
    if (a <= b) f(a) + sumF(a+1, b) else 0
  sumF
}

def sumLinear = sum(linear)
def sumSquare = sum(square)
def sumCube = sum(cube)

sumSquare(3, 10) + sumCubes(5, 20)

// We don't need to define the wrapper funcitons

sum(suquare)(3, 10) + sum(cube)(5, 20)

We can also write as follows :

def sum(f: Int => Int): (Int, Int) => Int =
  (a, b) => if (a <= b) f(a) + sum(f)(a+1, b) else 0

If compiler is not smart as we expected, above function should make anonymous function (a, b) => sth everytime sum(f) is called, so it could be slower than the function using sumF. (Because anonymous function doesn't have its own name, however, once sumF is defined, it is used without need to be declared again) But if the compiler optimizes this code(because sum(f) is used recursively), it may not be executed slow.

Or more simply, and probably the best way :

def sum(f: Int => Int)(a: Int, b: Int): Int =
  if (a <= b) f(a) + sum(f)(a+1, b) else 0

Currying and Uncurrying

A function of Type

(T1, T2, ... ,Tn) => T

can be turned into one of type

T1 => (T2 => (... Tn =>T)

This is called 'currying' named after Haskell Brooks Curry. The opposite direction is called 'uncurrying'.


Currying using Anonymous Functions

def foo(x: Int, y: Int, z: Int)(a: Int, b: Int) =
  x + y + z + a + b

val f1 = (x: Int, z: Int, b: Int) => foo(x, 1, z)(2, b)

val f2 = foo(_: Int, 1, _: Int)(2, _: Int)

val f3 = (x: Int, z: Int) => (b: Int) => foo(x, 1, z)(2, b)

f1(1, 2, 3)
f2(1, 2, 3)
f3(1, 2)(3)

Excercise : Cutty the mapReduce function

def mapReduce(combine: (Int,Int)=>Int,inival: Int,
f: Int=>Int, a: Int, b: Int): Int = {
if (a <= b) combine(f(a),mapReduce(combine,inival,f,a+1,b))
else inival
}

def sum(f: Int=>Int, a: Int, b: Int): Int =
mapReduce((x,y)=>x+y,0,f,a,b)

def product(f: Int=>Int, a: Int, b: Int): Int =
mapReduce((x,y)=>x*y,1,f,a,b)
  • Solution :
def mapReduce2(combine: (Int, Int) => Int, inival: Int)
              (f: Int => Int) (a : Int, b: Int): Int ={
    if (a <= b) combine(f(a), mapReduce2(combine, inival)(f)(a+1, b))
    else inival
}

// need to make a closure since mapReduce is param. code. 
def sum2 = mapReduce2((x, y) => x+y, 0) _

// val is better than def. Think about why.
// If you use 'def', you need to 'close' your code everytime is is called.
val product2 = mapReduce2((x, y) => x*y, 1) _


sum2(linear)(0,100)
product2(square)(1, 5)

You need to add '_'(underbar) after def sum2 so that it explicitly declares include methods invisible.

(Error message : missing argument list for method mapReduce2 in class. Unapplied methods are only converted to functions when a function type is expected. You can make this conversion explicit by writing mapReduce2 _ or mapReduce2(_,_)(_)(_,_) instead of mapReduce2.)


Exceptions

class factRangeException(val arg: Int) extends Exception

def fact(n: Int): Int =
    if (n < 0) throw new factRangeException(n)
    else if (n == 0) 1
    else n * fact(n -1)

def foo(n : Int) = fact(n + 10)

try {
    println(fact(3))
    println(foo(-100))
} catch {
    case e : factRangeException => {
        println("fact range error: " + e.arg)
    }
}

'Tutorials > Scala' 카테고리의 다른 글

Scala 7 - Datatypes2  (0) 2019.04.23
Scala 6 - Datatypes  (0) 2019.04.23
Scala 4 - Closures, revisted  (0) 2019.04.23
Scala 3 - Tail Recursion & Higher-Order Functions 1  (0) 2019.04.23
Scala 2 - Blocks in Scala & Lazy val  (0) 2019.04.23
Comments