What is 'Currying'?

前端 未结 18 1296
遥遥无期
遥遥无期 2020-11-21 05:26

I\'ve seen references to curried functions in several articles and blogs but I can\'t find a good explanation (or at least one that makes sense!)

相关标签:
18条回答
  • 2020-11-21 06:24

    A curried function is applied to multiple argument lists, instead of just one.

    Here is a regular, non-curried function, which adds two Int parameters, x and y:

    scala> def plainOldSum(x: Int, y: Int) = x + y
    plainOldSum: (x: Int,y: Int)Int
    scala> plainOldSum(1, 2)
    res4: Int = 3
    

    Here is similar function that’s curried. Instead of one list of two Int parameters, you apply this function to two lists of one Int parameter each:

    scala> def curriedSum(x: Int)(y: Int) = x + y
    curriedSum: (x: Int)(y: Int)Intscala> second(2)
    res6: Int = 3
    scala> curriedSum(1)(2)
    res5: Int = 3
    

    What’s happening here is that when you invoke curriedSum, you actually get two traditional function invocations back to back. The first function invocation takes a single Int parameter named x , and returns a function value for the second function. This second function takes the Int parameter y.

    Here’s a function named first that does in spirit what the first traditional function invocation of curriedSum would do:

    scala> def first(x: Int) = (y: Int) => x + y
    first: (x: Int)(Int) => Int
    

    Applying 1 to the first function—in other words, invoking the first function and passing in 1 —yields the second function:

    scala> val second = first(1)
    second: (Int) => Int = <function1>
    

    Applying 2 to the second function yields the result:

    scala> second(2)
    res6: Int = 3
    
    0 讨论(0)
  • 2020-11-21 06:27

    Currying is a transformation that can be applied to functions to allow them to take one less argument than previously.

    For example, in F# you can define a function thus:-

    let f x y z = x + y + z
    

    Here function f takes parameters x, y and z and sums them together so:-

    f 1 2 3
    

    Returns 6.

    From our definition we can can therefore define the curry function for f:-

    let curry f = fun x -> f x
    

    Where 'fun x -> f x' is a lambda function equivilent to x => f(x) in C#. This function inputs the function you wish to curry and returns a function which takes a single argument and returns the specified function with the first argument set to the input argument.

    Using our previous example we can obtain a curry of f thus:-

    let curryf = curry f
    

    We can then do the following:-

    let f1 = curryf 1
    

    Which provides us with a function f1 which is equivilent to f1 y z = 1 + y + z. This means we can do the following:-

    f1 2 3
    

    Which returns 6.

    This process is often confused with 'partial function application' which can be defined thus:-

    let papply f x = f x
    

    Though we can extend it to more than one parameter, i.e.:-

    let papply2 f x y = f x y
    let papply3 f x y z = f x y z
    etc.
    

    A partial application will take the function and parameter(s) and return a function that requires one or more less parameters, and as the previous two examples show is implemented directly in the standard F# function definition so we could achieve the previous result thus:-

    let f1 = f 1
    f1 2 3
    

    Which will return a result of 6.

    In conclusion:-

    The difference between currying and partial function application is that:-

    Currying takes a function and provides a new function accepting a single argument, and returning the specified function with its first argument set to that argument. This allows us to represent functions with multiple parameters as a series of single argument functions. Example:-

    let f x y z = x + y + z
    let curryf = curry f
    let f1 = curryf 1
    let f2 = curryf 2
    f1 2 3
    6
    f2 1 3
    6
    

    Partial function application is more direct - it takes a function and one or more arguments and returns a function with the first n arguments set to the n arguments specified. Example:-

    let f x y z = x + y + z
    let f1 = f 1
    let f2 = f 2
    f1 2 3
    6
    f2 1 3
    6
    
    0 讨论(0)
  • 2020-11-21 06:28

    Currying is when you break down a function that takes multiple arguments into a series of functions that each take only one argument. Here's an example in JavaScript:

    function add (a, b) {
      return a + b;
    }
    
    add(3, 4); // returns 7
    

    This is a function that takes two arguments, a and b, and returns their sum. We will now curry this function:

    function add (a) {
      return function (b) {
        return a + b;
      }
    }
    

    This is a function that takes one argument, a, and returns a function that takes another argument, b, and that function returns their sum.

    add(3)(4);
    
    var add3 = add(3);
    
    add3(4);
    

    The first statement returns 7, like the add(3, 4) statement. The second statement defines a new function called add3 that will add 3 to its argument. This is what some people may call a closure. The third statement uses the add3 operation to add 3 to 4, again producing 7 as a result.

    0 讨论(0)
  • 2020-11-21 06:28

    Here's a concrete example:

    Suppose you have a function that calculates the gravitational force acting on an object. If you don't know the formula, you can find it here. This function takes in the three necessary parameters as arguments.

    Now, being on the earth, you only want to calculate forces for objects on this planet. In a functional language, you could pass in the mass of the earth to the function and then partially evaluate it. What you'd get back is another function that takes only two arguments and calculates the gravitational force of objects on earth. This is called currying.

    0 讨论(0)
  • 2020-11-21 06:28

    Here you can find a simple explanation of currying implementation in C#. In the comments, I have tried to show how currying can be useful:

    public static class FuncExtensions {
        public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
        {
            return x1 => x2 => func(x1, x2);
        }
    }
    
    //Usage
    var add = new Func<int, int, int>((x, y) => x + y).Curry();
    var func = add(1);
    
    //Obtaining the next parameter here, calling later the func with next parameter.
    //Or you can prepare some base calculations at the previous step and then
    //use the result of those calculations when calling the func multiple times 
    //with different input parameters.
    
    int result = func(1);
    
    0 讨论(0)
  • There is an example of "Currying in ReasonML".

    let run = () => {
        Js.log("Curryed function: ");
        let sum = (x, y) => x + y;
        Printf.printf("sum(2, 3) : %d\n", sum(2, 3));
        let per2 = sum(2);
        Printf.printf("per2(3) : %d\n", per2(3));
      };
    
    0 讨论(0)
提交回复
热议问题