Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should calling a currying function with non-complete args with underscore

Tags:

scala

currying

According to ScalaByExample:

A curried function definition def f (args1) ... (argsn) = E where n > 1 expands to

def f (args1) ... (argsn−1) = { def g (argsn) = E ; g }

Or, shorter, using an anonymous function:

def f (args1) ... (argsn−1) = ( argsn ) => E

Uncurried version:

def f(x: Int): Int => Int = {
    y: Int => x * y
}                                             //> f: (x: Int)Int => Int

def f1 = f(10)                                //> f1: => Int => Int
f1(5)     

Curried version:

def g(x: Int)(y: Int) = {
    x * y
}                                             //> g: (x: Int)(y: Int)Int

def g1 = g(10) _                              //> g1: => Int => Int
g1(5)  

The question is, Why curried required the underscore in line #5 in the second code snippet.

like image 996
Muhammad Hewedy Avatar asked Jul 03 '26 09:07

Muhammad Hewedy


2 Answers

You can find the explanation at Martin Odersky book: http://www.artima.com/pins1ed/functions-and-closures.html (search for "Why the trailing underscore").

In short this is because Scala is closer to Java in a lot of things, rather than functional languages where this is not required. This helps you to find out mistakes at compile time, if you forgot the missing argument.

If underscore was not required, the next code will compile:

println(g(10))

And this check helps you preventing such mistakes

There are some cases though, when such calls are obvious, and underscore is not required:

def g(x: Int)(y: Int) = {
    x * y
}

def d(f: Int => Int) {
  f(5)
}

d(g(10))   // No need to write d(g(2) _)

// Or any other way you can specify the correct type
val p: Int => Int = g(10)
like image 193
Archeg Avatar answered Jul 06 '26 11:07

Archeg


Something to note: in Scala, def's are methods, not functions, at least, not directly. Methods are converted to functions by the compiler every time a method is used where a function would be required, but strictly speaking, a function would be created with val instead, like so:

val curry = (x: Int) => (y: Int) => x * y

This allows you to apply arguments one at a time without having to add a trailing underscore. It functions identically to the code in your first snippet, but because it uses val and not def, curry cannot be written like

val curry(x: Int) = (y: Int) => x * y //Won't compile

So, when you want to write a function that behaves the way you want a curried function to behave, write it like I did in my first snippet. You can keep chaining parameters with => as many times as you want (up to technical limits, but good luck hitting them).

like image 35
Nicholas Montaño Avatar answered Jul 06 '26 09:07

Nicholas Montaño



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!