views:

812

answers:

3

I'm learning more about Scala and I'm having a little trouble understanding the example of anonymous functions here http://www.scala-lang.org/node/135. I've copied the entire code block below:

object CurryTest extends Application {
  def filter(xs: List[Int], p: Int => Boolean): List[Int] =
    if (xs.isEmpty) xs
    else if (p(xs.head)) xs.head :: filter(xs.tail, p)
    else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2)))
println(filter(nums, modN(3)))
}

I'm confused with the application of the modN function

def modN(n: Int)(x: Int) = ((x % n) == 0)

In the example, it's called with 1 argument

modN(2) and modN(3)

Can someone clarify what the syntax of modN(n: Int)(x: Int) means? Since it's called with 1 argument, I'm assuming they're not both arguments, but I can't really figure out how the values from nums get used by the mod function.

thanks, Jeff

+2  A: 

In that example, modN returns a function that mods by the particular N. It saves you from having to do this:

def mod2(x:Int): Boolean = (x%2) == 0
def mod3(x:Int): Boolean = (x%3) == 0

The two pairs of parens delimit where you can stop passing arguments to the method. Of course, you can also just use a placeholder to achieve the same thing even when the method only has a single argument list.

def modN(n: Int, x: Int): Boolean = (x % n) == 0

val nums = List(1, 2, 3, 4, 5)
println(nums.filter(modN(2, _)))
println(nums.filter(modN(3, _)))
David Winslow
Thank you for the detailed response. In this second example with the placeholder, can you explain what the last : Int is for, i.e.: def modN(n: Int)(x: Int): Intvs def modN(n: Int)(x: Int)Is that just syntax difference when a placeholder can be used and when it can't?
Jeff Storey
Also, I just tried that second example with the placeholder _, and the compiler complains that modN has the wrong number of arguments.
Jeff Storey
That's because `modN(x, y)` is not a valid way of calling the function (Scala does not do automatic uncurrying - i.e. transforming from `f(x)(y)` to `f(x, y)`). Therefore, the correct way to call `modN` in the example would be `modN(2)(_)`. Also, small nitpick - the return type of `modN` is incorrect, it should be `modN(n: Int)(x: Int): Boolean = (x % n) == 0`. Or you could let the type inferer infer it. :)
Flaviu Cipcigan
I updated the second example to be less wrong. Thanks for the explanation Flaviu.
David Winslow
+2  A: 

You are partially applying the ModN function. Partial function application is one of the main features of functional languages. For more information check out these articles on Currying and Pointfree style.

mdm
+13  A: 

This is a fun thing in functional programming called currying. Basically Moses Schönfinkel and latter Haskell Curry (Schonfinkeling would sound weird though...) came up with the idea that calling a function of multiple arguments, say f(x,y) is the same as the chain of calls {g(x)}(y) or g(x)(y) where g is a function that produces another function as its output.

Take as an example the function f(x: Int, y: Int) = x + y. A call to f(2,3) would produce 5, as expected. But what happens when we curry this function - redefine it as f(x:Int)(y: Int)and call it as f(2)(3). The first call, f(2) produces a function taking an integer y and adding 2 to it -> therefore f(2) has type Int => Int and is equivalent to the function g(y) = 2 + y. The second call f(2)(3) calls the newly produced function g with the argument 3, therefore evaluating to 5, as expected.

Another way to view it is by stepping through the reduction (functional programmers call this beta-reduction - it's like the functional way of stepping line by line) of the f(2)(3) call (note, the following is not really valid Scala syntax).

f(2)(3)         // same as x => {y => x + y}
 | 
{y => 2 + y}(3) // the x in f gets replaced by 2
       |
     2 + 3      // the y gets replaced by 3
       |
       5

So, after all this talk, f(x)(y) can be viewed as just the following lambda expression (x: Int) => {(y: Int) => x + y} - which is valid Scala.

Hope this all makes sense - I tried to give a bit of a background of why the modN(3) call makes sense :)

-- Flaviu Cipcigan

Flaviu Cipcigan
Excellent explanation. I changed yours to the accepted answer (plus you fixed the error in the previous example).
Jeff Storey