Swift: Benefits of Curry Function

Swift: Benefits of Curry Function

The problem is that the example given isn't an example of currying exactly. That's why you don't see any value in it.

This is a better example of currying:

class MyHelloWorldClass {
//Function that takes two arguments
func concatenateStrings(string1: String, string2: String) {
return "\(string1)\(string2)"
}
//Curried version of concatenateStrings that takes one argument.
func helloWithName(name: String) -> String {
return concatenateStrings("hello, ", name)
}
}

This is a better example of how function variables are curried functions in Swift: http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/

What is 'Currying'?

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); // returns 7

var add3 = add(3); // returns a function

add3(4); // returns 7
  • 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 may call a closure.)
  • The third statement uses the add3 operation to add 3 to 4, again
    producing 7 as a result.

Need help in understanding types (based on curry)

I believe the source of your confusion is this passage:

the curry function takes function f a b

Not really: curry takes a function, and that function is f. As for a and b, they are arguments that are passed to the curried function. It is easier to see that by either adding a pair of superfluous parentheses, to make the partial application more evident...

(curry f) a b = f (a,b)

... or by shifting a and b to the right-hand side with a lambda:

curry f = \a b -> f (a,b)

f is a function that takes a pair -- note that we give it a pair, (a,b). curry f, on the other hand, takes the two arguments separately. That being so, the type of curry is indeed:

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

Swift - A function with double parentheses?

As mentioned in the comments this would be referred to as Curried Functions.

Basically it gives you the ability to dynamically create functions with more specificity than a function would have if you sent in all the params.

Example time (this is a rather dumb example but it should give you an idea of what currying does)

func addNumbers(a a: Int, b: Int) -> Int {
return a + b
}

func addNumbers(a a: Int)(b: Int) -> Int {
return a + b
}

//usage normal function
var two = addNumbers(a:1, b:1)
var three = addNumbers(a:1, b:2)
var four = addNumbers(a:1, b:3)

//usage curried function
var addOne = addNumbers(a:1)
var two = addOne(b:1)
var three = addOne(b:2)
var four = addOne(b:3)

So if you have some problem that you know will be solved with one value for one of your params in some specific case but another value in another situation you can save yourself from sending in those parameters and instead just create the function where it will be used.

Again as I wrote above this was a dumb example but it can be very useful when writing a REST api as an example. Where you have the same functions applied to a lot of different types which can be saved in the same general way.

Another usage example Logger implemented with Currying

In your example the function for mapping objects can be applied first and then the created mapping function can be applied to the sources that should be mapped.

You can read more about it here and here

Are these two curry function implementations equal?

Yes, they are identical. If you compile:

object Test {
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => f(a, _)

def curry2[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => (b: B) => f(a, b)
}

with -Xprint:typer, you get the intermediate abstract syntax tree:

[[syntax trees at end of                     typer]]
package <empty> {
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super.<init>();
()
};
def curry[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((x$1: B) => f.apply(a, x$1)));
def curry2[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((b: B) => f.apply(a, b)))
}
}

During the "typer" stage, when the compiler assigns types to everything, it realizes that the _ (now named x$1) must be type B.



Related Topics



Leave a reply



Submit