84

I realize that there are several questions on here about what currying and partially applied functions are, but I'm asking about how they are different. As a simple example, here is a curried function for finding even numbers:

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)

So you could write the following to use this:

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

which returns: List(2,4,6,8). But I've found that I can do the same thing this way:

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

val p = modN(2, _: Int)
println(filter(nums, p))

which also returns: List(2,4,6,8).

So my question is, what's the main difference between the two, and when would you use one over the other? Is this just too simplistic of an example to show why one would be used over the other?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Eric
  • 1,688
  • 2
  • 15
  • 13
  • When partially applied, the costs of representing a curried and non-curried version in memory *might* be different, so the runtime performance might be influenced too. (That is, if the optimizer isn't smart enough to choose the optimal representation in both cases.) I'm not familiar enough with Scala to say what the exact differences are, though. –  Jan 13 '13 at 23:41
  • 1
    Have a look at this one: http://stackoverflow.com/questions/8063325/usefulness-as-in-practical-applications-of-currying-v-s-partial-application-i – Utaal Jan 14 '13 at 01:47
  • I found this explanation very very useful, he explains about partial functions, partially applied functions and currying, all in one post:http://stackoverflow.com/a/8650639/1287554 – Plasty Grove Jan 14 '13 at 05:41
  • And thank you @Utaal for your link. Any answer from Martin Odersky himself is very valued. I think these concepts are starting to click now. – Eric Jan 14 '13 at 15:16

5 Answers5

89

The semantic difference has been explained fairly well in the answer linked to by Plasty Grove.

In terms of functionality, there doesn't seem much of a difference, though. Let's look at some examples to verify that. First, a normal function:

scala> def modN(n: Int, x: Int): Boolean = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>

So we get a partially applied <function1> that takes an Int, because we've already given it the first integer. So far so good. Now to currying:

scala> def modNCurried(n: Int)(x: Int): Boolean = ((x % n) == 0)

With this notation, you'd naively expect the following to work:

scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
          modNCurried(5)

So the multiple parameter list notation doesn't really seem to create a curried function right away (assumingly to avoid unnecessary overhead) but waits for you to explicitly state that you want it curried (the notation has some other advantages as well):

scala> modNCurried(5) _
res24: Int => Boolean = <function1>

Which is exactly the same thing we got before, so no difference here, except for notation. Another example:

scala> modN _
res35: (Int, Int) => Boolean = <function2>

scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>

This demonstrates how partially applying a "normal" function results in a function that takes all parameters, whereas partially applying a function with multiple parameter lists creates a chain of functions, one per parameter list which, all return a new function:

scala> def foo(a:Int, b:Int)(x:Int)(y:Int): Int = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>

scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.

As you can see, because the first parameter list of foo has two parameters, the first function in the curried chain has two parameters.


In summary, partially applied functions aren't really different form curried functions in terms of functionality. This is easily verified given that you can convert any function to a curried one:

scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1

scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>

Post Scriptum

Note: The reason that your example println(filter(nums, modN(2)) works without the underscore after modN(2) seems to be that the Scala compiler simply assumes that underscore as a convenience for the programmer.


Addition: As @asflierl has correctly pointed out, Scala doesn't seem to be able to infer the type when partially applying "normal" functions:

scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))

Whereas that information is available for functions written using multiple parameter list notation:

scala> modNCurried(5) _
res3: Int => Boolean = <function1>

This answers shows how this can be very useful.

nilskp
  • 3,097
  • 1
  • 30
  • 34
fresskoma
  • 25,481
  • 10
  • 85
  • 128
20

Currying is to do with tuples: turning a function that takes a tuple argument into one that takes n separate arguments, and vice versa. Remembering this is the key to distinguishing curry vs partial application, even in languages that don't cleanly support currying.

curry :: ((a, b) -> c) -> a -> b -> c 
   -- curry converts a function that takes all args in a tuple
   -- into one that takes separate arguments

uncurry :: (a -> b -> c) -> (a, b) -> c
   -- uncurry converts a function of separate args into a function on pairs.

Partial application is the ability to apply a function to some arguments, yielding a new function for the remaining arguments.

It is easy to remember if you just think currying is the transformation to do with tuples.

In languages that are curried by default (such as Haskell) the difference is clear -- you have to actually do something to pass arguments in a tuple. But most other languages, including Scala, are uncurried by default -- all args are passed as tuples, so curry/uncurry is far less useful, and less obvious. And people even end up thinking that partial application and currying are the same thing -- just because they can't represent curried functions easily!

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
  • I fully agree. In Scala terms "currying" in the original meaning of the word is the "process of transforming" a function with one parameter list to a function with multiple parameter lists. In Scala this transformation can be executed using ".curried". Unfortunately, Scala seems to have overloaded the meaning of the word a bit since originally it would rather be called ".curry" instead of ".curried". – Fatih Coşkun May 17 '15 at 08:49
2

Multivariable function:

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

Currying (or the curried function):

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

So it's not partially applied function that's comparable to currying. It's the multivariable function. What's comparable to partially applied function is the invocation result of a curried function, which is a function with the same parameter list that the partially applied function has.

lcn
  • 2,239
  • 25
  • 41
1

The best explanation I could find so far: https://dzone.com/articles/difference-between-currying-amp-partially-applied

Currying: decomposition of functions with multiple arguments into a chain of single-argument functions. Notice, that Scala allows passing a function as an argument to another function.

Partial application of function: pass to a function fewer arguments than it has in its declaration. Scala does not throw an exception when you provide fewer arguments to the function, it simply applies them and returns a new function with rest of arguments that need to be passed.

Community
  • 1
  • 1
Danylo Zatorsky
  • 5,856
  • 2
  • 25
  • 49
0

Just to clarify on the last point

Addition: As @asflierl has correctly pointed out, Scala doesn't seem to be able to infer the type when partially applying "normal" functions:

Scala can infer types if all parameters are wildcards but not when some of them are specified and some of them not.

scala> modN(_,_)
res38: (Int, Int) => Boolean = <function2>

scala> modN(1,_)
<console>:13: error: missing parameter type for expanded function ((x$1) => modN(1, x$1))
       modN(1,_)
              ^
Sud
  • 183
  • 1
  • 7