Scala literal function (syntax) - two versions, same result - what is the difference?

97 views Asked by At

I'm a Scala beginner. Can someone explain me what is the difference (except syntax) between these two lines of code (though they return the same result)? I wrote them practicing literal functions and try to find out if there is anything up 'behind the scene'?

val literal1 = (fn: Int => Int, x: Int) => fn(x)

val literal2 = (fn: Int => Int) => (x: Int) => fn(x)          

I see that there is a possibility of passing arguments into functions in different ways. But does it really matter which way I choose (except of currying case)?

literal1(p => p + 1, 2) /*3*/

literal2(p => p + 1)(2) /*3*/
1

There are 1 answers

0
Tim Moore On

These two values have different types:

val literal1: (Int => Int, Int) => Int = <function>
val literal2: (Int => Int) => (Int => Int) = <function>

In other words, literal1 is a function that takes two arguments—a function that takes an Int and returns an Int, and an Int—and returns an Int.

On the other hand, literal2 is a function that takes one argument—a function that takes an Int and returns an Int, and returns a function that takes an Int and returns an Int.

Other than the different calling convention, the second form allows you to easily partially apply the first parameter, returning a function that takes an Int and returns an Int:

val doubler = literal2(_ * 2) // val doubler: Int => Int = <function>

doubler(2) // val res0: Int = 4
doubler(5) // val res1: Int = 10

Doing the same with the first form requires very slightly more complex syntax:

val doubler = literal1(_ * 2, _)

doubler(2)
doubler(5)

The first form can be transformed automatically to the second using its curried method:

val literal3 = literal1.curried // val literal3: (Int => Int) => (Int => Int) = scala.Function2<function>

literal3(_ * 3)(6) // val res2: Int = 18

Note that it is conventional in Scala for functions and methods that take a single function argument to specify it as the final argument in a curried format, as this allows for a convenient syntax for a multi-line lambda:

val literal4 = (x: Int) => (fn: Int => Int) => fn(x)

literal4(25) { x =>
  val mod = x % 2
  if (mod == 0) println("even")
  else println("odd")
  mod
}

Output:

val literal4: Int => ((Int => Int) => Int) = <function>

odd
val res3: Int = 1