19

Everywhere I look, I see the terms multiple parameter lists and currying used interchangably. I see it in dozens of stackoverflow questions, and even on scala-lang.org. This page, for example, has the title "Currying". And the first sentence? "Methods may define multiple parameter lists."

And yet some very knowledgeable people get annoyed when they see multiple parameter lists and currying equated. I posted an answer to this question but then deleted it when I saw Randall Schulz's comment because I was afraid I might be inadvertently spreading misinformation. My understanding was that a function with multiple parameter lists is necessarily a curried function, but that function currying can be achieved in other ways as well (the top answer to this question lists four ways), but I'm not sure that's the whole story. I want to really understand the distinction.

I know there are a lot of very similar questions to this one on stackoverflow, but I haven't found one that precisely spells out the difference. What do I need to understand about multiple parameter lists and currying in order to speak accurately about them?

Community
  • 1
  • 1
Matt Malone
  • 361
  • 4
  • 25

1 Answers1

25

I hope you don't mind if I start with a Haskell example, since Haskell is a vastly simpler language than Scala. In Haskell all functions are functions in the mathematical sense—they take one argument and return one value. Haskell also has tuples, and you can write a function that looks a little like it takes multiple parameters, as a function from a tuple to whatever. For example:

Prelude> let add = (\(x, y) -> x + y) :: (Int, Int) -> Int
Prelude> add (1, 2)
3

Now we can curry this function to get a function with type Int -> Int -> Int instead of (Int, Int) -> Int:

Prelude> let curriedAdd = curry add

This allows us to partially apply the function, for example:

Prelude> let add3 = curriedAdd 3
Prelude> add3 1
4

So we have a nice clean definition of currying—it's a function that takes a function with a tuple (specifically a pair) for an argument and returns a function that takes as an argument the first type in the pair and returns a function from the second type in the pair to the original return type. Which is just a wordy way to say this:

Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c

Okay, now for Scala.

In Scala you can also have functions that take a tuple argument. Scala also has "functions" that take more than one argument (Function2 and up). These are (confusingly) different kinds of animals.

Scala also has methods, which are different from functions (although they can be converted to functions more or less automatically via eta expansion). Methods can have multiple parameters, or tuple parameters, or multiple parameter lists.

So what does it mean to say we're currying something in this context?

Most literally, currying is something you do with a Function2 (and up):

scala> val add: Function2[Int, Int, Int] = (x: Int, y: Int) => x + y
add: (Int, Int) => Int = <function2>

scala> val curriedAdd = add.curried
curriedAdd: Int => (Int => Int) = <function1>

scala> val add3 = curriedAdd(3)
add3: Int => Int = <function1>

This is about the same as what we saw in the Haskell case, except that we're currying a function with multiple arguments, which is something that doesn't properly exist in Haskell.

Now I'm pretty sure this is the only context in which the word curry actually appears in the Scala standard library (not counting the accompanying uncurried on the Function companion object), but given the enormous mess that Scala makes of the idea of methods, functions, etc. (don't get me wrong—I love Scala, but this part of the language is a complete disaster), it seems pretty reasonable to me to apply the word in the following context as well:

def add(x: Int, y: Int) = x + y
def curriedAdd(x: Int)(y: Int) = add(x, y)

Here we've turned a method that takes two parameters into a method with multiple parameter lists—each of which only takes a single parameter (this last part is important).

And in fact the language specification also uses the term in this context, describing the following as "a single, curried function definition":

def func(x: Int)
        (y: Int) = x + y

(Which is of course confusing as hell, since this is a method, not a function.)

So to sum up: multiple parameter lists are one way to implement currying in Scala, but not all methods with multiple parameter lists are curried—only ones where each parameter list has a single parameter. And all the terminology is pretty mushy, anyway, so don't worry too much about getting it right.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • It might be worth mentioning for completeness that `Function2` also has a `tupled` method, taking the function from `(A,B) => C` to `((A,B)) => C`. Adding to the potential confusion, Scala's optional parentheses feature gives the ability to call both forms as `f(a,b)`. – Kristian Domagala Nov 12 '13 at 00:49
  • 1
    @Kristian: If you don't mind I think I'll let your comment be the only pointer to that minefield, since tupling and currying seem mostly orthogonal (and let's hope that someday all this stuff gets unified). – Travis Brown Nov 12 '13 at 00:56
  • Fair point. I won't be holding my breath on unification though; not in Scala anyway ;-) – Kristian Domagala Nov 12 '13 at 01:36
  • 2
    In the Scala specification, there are no methods, there are only functions. What we most often call functions are, by the specification, _anonymous functions_. So one uses eta-expansion to convert from a function to an anonymous function. There's a few more weird stuff around that -- I have that on an answer somewhere, but "enormous mess" sounds right to me. – Daniel C. Sobral Nov 12 '13 at 01:46
  • Daniel's probably thinking of http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala – Seth Tisue Nov 12 '13 at 02:49
  • If I have understood, a function with multiple parameter lists, all having _exactly one parameter_, **is** curried. foldLeft, for example, is curried as it has two parameter lists of one parameter each. The only practical distinction one may draw is that not all multiple parameter list functions are curried (i.e. if a list includes multiple parameters), and curried functions are not always specified as multiple parameter list functions. – Matt Malone Nov 12 '13 at 16:38
  • "functions in the mathematical sense—they take one argument and return one value"; since when is that a requirement of a mathematical function? – 0__ Nov 12 '13 at 16:54
  • @0__: A function in this sense maps inputs to outputs. The domain may be the product of two or more sets, but there's still just one input. – Travis Brown Nov 12 '13 at 17:07
  • @TravisBrown well I would call this hairsplitting. Certainly no justification of putting the word function in ticks when talking about Scala. – 0__ Nov 12 '13 at 18:59
  • @0__: My objection is that Scala has product types and could use them to implement multi-argument functions, but instead does both. – Travis Brown Nov 12 '13 at 19:25
  • Originally they were just routines and subroutines, but when "routine programming" didn't take off, one day Odersky did a global replace with function, but forgot the /g. Next time he went over the spec, he did another replace with the word method. As Prof Odersky is fond of saying, Some great designs are not invented but discovered through a series of extraordinary accidents. – som-snytt Nov 17 '13 at 01:54