A coworker of mine sent me a question as follows:
Implement a HOF(higher order function) that performs currying, the signature of your function is as follows:
def curry[A,B,C](f:(A,B) => C) : A => B => C
Similarly, implement a function that performs uncurrying as follows:
def uncurry[A,B,C](f:A => B => C): (A,B) => C
The way I understand currying is that if you have a function that takes multiple parameters, you can repeatedly apply the function to each one of the paramaters until you get the result.
So something along the lines of f:(A,B) => C
turns into A => f(A,_) => f(B)
????
And uncurrying would be to consolidate this application into one function as follows:
f:A=>B=>C
would be f(A,B)
?
Maybe I am just being confused by the syntax here but it would be great if somebody could point out what I am missing here.
Thanks
Hopefully this fully worked example with a bunch of comments is easy to understand. Please reply if you have questions.
You can execute this code by dropping it in a Scala interpreter.
// Here's a trait encapsulating the definition your coworker sent.
trait Given {
def curry[A,B,C](f:(A,B) => C) : A => B => C
def uncurry[A,B,C](f:A => B => C): (A,B) => C
}
object Impl extends Given {
// I'm going to implement uncurry first because it's the easier of the
// two to understand. The bit in curly braces after the equal sign is a
// function literal which takes two arguments and applies the to (i.e.
// uses it as the arguments for) a function which returns a function.
// It then passes the second argument to the returned function.
// Finally it returns the value of the second function.
def uncurry[A,B,C](f:A => B => C): (A,B) => C = { (a: A, b: B) => f(a)(b) }
// The bit in curly braces after the equal sign is a function literal
// which takes one argument and returns a new function. I.e., curry()
// returns a function which when called returns another function
def curry[A,B,C](f:(A,B) => C) : A => B => C = { (a: A) => { (b: B) => f(a,b) } }
}
def add(a: Int, b: Long): Double = a.toDouble + b
val spicyAdd = Impl.curry(add)
println(spicyAdd(1)(2L)) // prints "3.0"
val increment = spicyAdd(1) // increment holds a function which takes a long and adds 1 to it.
println(increment(1L)) // prints "2.0"
val unspicedAdd = Impl.uncurry(spicyAdd)
println(unspicedAdd(4, 5L)) // prints "9.0"
How about a less numerical example?
def log(level: String, message: String) {
println("%s: %s".format(level, message))
}
val spicyLog = Impl.curry(log) // spicyLog's type is String => Unit
val logDebug = spicyLog("debug") // This new function will always prefix the log
// message with "debug".
val logWarn = spicyLog("warn") // This new function will always prefix the log
// message with "warn".
logDebug("Hi, sc_ray!") // prints "debug: Hi, sc_ray!"
logWarn("Something is wrong.") // prints "warn: Something is wrong."
Update
You replied asking "How does the compiler evaluate expressions such as a => b => f(a,b)
." Well it doesn't. At least the way things are defined in your coworker's snippet, that wouldn't compile. In general, though, if you see something of the form A => B => C
that means "a function which takes an A as an argument; it returns a function which takes a B as an argument and returns a C."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With