Wednesday, November 20, 2013

Introduction to Currying in Scala

Scala and functional programming

I have recently moved to programming in Scala. I started with 1 book and have now completed Functional Programming Principles in Scala , a free course on coursera. I am also part way into the next course on Principles of Reactive Programming.So far I have been having a ton of fun, and been blown away at the power of functional programming. I wanted to share some notes that helped me to understand some of the topics that I have studied.

Introduction to Currying in Scala


What is Currying
Currying is named after "Haskell Brooks Curry" a mathematician and logician.
Looking at A Tour of Scala: Currying: "Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments."
Currying is a way of applying partial functions in an effort to make your code operate or appear more like built in language constructs thus making it more readable.

Here is some text from the book "Programming in Scala: A Comprehensive Step-by-Step Guide"
Currying allows you to make new control abstractions that feel like native language.... and, A curried function is applied to multiple arguments lists instead of just one.

Partial Functions
To better understand Currying we must take a look at partial functions. Functions in Scala and other functional languages are first class objects. These objects are generated for you by the compiler and contain a method apply. When you call a function

def f = {}
f()        // you are actually calling f.apply()

One of the things we can do with a function that contains a number of arguments is to supply "some" of the arguments. The compiler will again generate a function for you but this time it will also generate a wrapper with the partially applied values. Lets take a look at this in a Scala worksheet.

def mul3( a: Int, b: Int, c:Int ): Int = {
 a * b * c
}                                         // mul3: (a: Int, b: Int, c: Int)Int
mul3( 2, 2, 2)                            // res0: Int = 8

val partial = mul3( 5, _: Int , 5 )       // partial  : Int => Int = >function1<

Note that the compiler gave us a >function1<. This is a function that takes a single parameter, in our case the middle parameter to the original function that we left as a place holder. What was actually generated would be something similar to the following.

def f1( b: Int ): Int = {
   mul3(5, b, 5)
}

Currying
So now that we have some background lets take a look at a curried function. We will write a function prod and then show the equivalent curried function curriedProd

def prod( a: Int, b: Int) = { a * b }     //> prod: (a: Int, b: Int)Int

def curriedProd(a: Int)( b: Int) = { a * b }
                                                  //> curriedProd: (a: Int)(b: Int)Int

When you envoke the curried function you actually get another function with one of the arguments applied to it. This can be seen by supplying a place holder to the curried function as follows

val timesThree = curriedProd(3)_          //> timesThree  : Int => Int = 
 
val result = timesThree(3)                //> result  : Int = 9                                                  //> curriedProd: (a: Int)(b: Int)Int

Now that we have seen how currying works. We can now look at a number of uses.

Function Calling Syntax
Lets again define a simple function. This function takes a single parameter and adds five to its value. There are actually 2 different function calling syntax (there are actually more then 2). One that uses the normal parenthesis for arguments () and another method that uses curly braces or block syntax {}. Lets take a look at an example

def plusFive( x: Int ) = {
  x + 5
 }                                         //> plusFive: (x: Int)Int
 
val b = plusFive(10)                      //> b  : Int = 15
val c = plusFive{ 10 }                    //> c  : Int = 15

The purpose of substituting curly braces for parenthesis is to enable client programmers to write function literals between curly braces. One thing to note however is that we can only supply this kind of syntax if the function has a single argument. But wait !! Using currying it is always possible to break arguments out into their own argument list, thus yielding a function with a single parameter. Here is a small example.

def applyOpt( a: Int, b: Int, op: (Int, Int) => Int) = {
  op( a, b )
 }                                         //> applyOpt: (a: Int, b: Int, op: (Int, Int) => Int)Int
 
 applyOpt( 3, 3, (a: Int, b: Int) => { a * b } )
                                                  //> res2: Int = 9
 
 
 
 def applyOpt2( a: Int, b: Int)(op: (Int, Int) => Int) = {
  op( a, b )
 }                                         //> applyOpt2: (a: Int, b: Int)(op: (Int, Int) => Int)Int
 
 
 applyOpt2( 4, 4 ){ (a,b) => a*b }         //> res3: Int = 16
// or even..
applyOpt2( 4, 4 ){ _ * _ }                //> res3: Int = 16

Now that we have seen how this works it is time to put it all together in a real world example.


The Loan Pattern

The loan pattern is a way of lending resources to the caller while managing the lifecycle of those resources when they are no longer used. Coming from a C# background this is exactly the purpose of the "using" key word in C# .net

Lets finish off with a concrete example of this pattern in action.


def withOutput(f: OutputStream => Any) {
  val out: OutputStream = getOutputStream()
 
  try {
    f(out)
    out.flush()
  }
  finally {
    out.close() 
  }
}

// Now we can write...
withOutput { out => out.write(response.getBytes()) }


No comments:

Post a Comment