What's the difference between currying and multiple parameter lists?

前端 未结 1 897
感动是毒
感动是毒 2021-01-07 19:47

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. Th

相关标签:
1条回答
  • 2021-01-07 20:31

    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.

    0 讨论(0)
提交回复
热议问题