15

I'm learning more about Scala, and I'm having a little trouble understanding the example of anonymous functions in 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 one argument

modN(2) and modN(3)

What does the syntax of modN(n: Int)(x: Int) mean?

Since it's called with one 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.

3 Answers 3

48

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.

As an example, take 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.

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

Sign up to request clarification or add additional context in comments.

2 Comments

Excellent explanation. I changed yours to the accepted answer (plus you fixed the error in the previous example).
Upvote for "Schonfinkeling" a parameter into a function. I'll only use this word from now on. :-D
3

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.

Comments

2

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, _)))

4 Comments

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): Int vs def modN(n: Int)(x: Int) Is that just syntax difference when a placeholder can be used and when it can't?
Also, I just tried that second example with the placeholder _, and the compiler complains that modN has the wrong number of arguments.
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. :)
I updated the second example to be less wrong. Thanks for the explanation Flaviu.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.