Function Declaration
In general, functions in Scala have the following pattern:
def foo([parameters]): [return type] = expression
A simple example is the sum of two numbers:
def sum(a: Int, b: Int): Int = {
return a + b
}
The return statement can be omitted since Scala always returns the value of the last expression in a function:
def sumWithoutReturn(a: Int, b: Int): Int = {
a + b
}
Because Scala expects an expression after the equal sign, it is possible to shorten this example to the following:
def sumShort(a: Int, b: Int): Int = a + b
The return type can be omitted as well since Scala knows what it has to expect as return type (if you add two integers the sum will also be an integer). This feature is called type inference.
def sumShortest(a: Int, b: Int) = a + b
If you don't want to return a value and you want to indicate this, you can use Unit
as return type which is similar to void
in Java.
def printSum(a: Int, b: Int): Unit = println(a + b)
Anonymous Functions
Anonymous functions are lightweight functions, which can be defined without a need to assign a name.
The following is an anonymous function which takes in two integers and returns their sum.
(x: Int, y: Int) => x + y
They can be assigned to val
s :
val sum = (x: Int, y: Int) => x + y
They are mainly used however as arguments to other functions. For instance, the map
function on collections expects another function as its argument :
// Returns Seq("FOO", "BAR", "QUX")
Seq("Foo", "Bar", "Qux").map((x: String) => x.toUpperCase)
The types of the arguments of the anonymous function can be omitted, they will be infered automatically :
Seq("Foo", "Bar", "Qux").map((x) => x.toUpperCase)
If there is just one argument, parenthesis around it can be omitted too :
Seq("Foo", "Bar", "Qux").map(x => x.toUpperCase)
Underscores shorthand
There is an even shorter syntax, which doesn't require you to name the arguments. The above snippet can also be written :
Seq("Foo", "Bar", "Qux").map(_.toUpperCase)
_
represents the anonymous function arguments positionally. So if you have an anonymous function with multiple parameters, each occurrence of _
will refer to a different argument. For instance, the two following expressions are equivalent :
// Returns "FooBarQux" in both cases
Seq("Foo", "Bar", "Qux").reduce((s1, s2) => s1 + s2)
Seq("Foo", "Bar", "Qux").reduce(_ + _)
With this shorthand however you can not refer to the same argument twice, nor refer to them in a different order.
Anonymous function with zero parameters
If you want to create a value for an anonymous function which does not take parameters, leave the parameter list blank:
val sayHello = () => println("hello")
Call-by-name and call-by-value
Call-by-name parameters are evaluated each time they are used within a function, rather than once at the point the function is applied.
def callByValue(x: Int) = {
println(s"Inside function - arg = $x")
x
}
callByValue({println("Evaluating byValue argument"); 5})
// Evaluating byValue argument
// Inside function - arg = 5
// res0: Int = 5
def callByName(x: => Int) = {
println(s"Inside function - arg = $x")
x
}
callByName({println("Evaluating byName argument"); 5})
// Evaluating byName argument
// Inside function - arg = 5
// Evaluating byName argument
// res1: Int = 5
Currying
Currying, according to Wikipedia,
is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions.
Concretely, in terms of scala types, in the context of a function that take two arguments, (has arity 2) it is the conversion of
val f: (A, B) => C // a function that takes two arguments of type `A` and `B` respectively
// and returns a value of type `C`
to
val curriedF: A => B => C // a function that take an argument of type `A`
// and returns *a function*
// that takes an argument of type `B` and returns a `C`
So for arity-2 functions we can write the curry function as:
def curry[A, B, C](f: (A, B) => C): A => B => C = {
(a: A) => (b: B) => f(a, b)
}
Usage:
val f: (String, Int) => Double = {(_, _) => 1.0}
val curriedF: String => Int => Double = curry(f)
f("a", 1) // => 1.0
curriedF("a")(1) // => 1.0
Scala gives us a few language features that help with this:
- You can write curried functions as methods. so
curriedF
can be written as:
def curriedFAsAMethod(str: String)(int: Int): Double = 1.0
val curriedF = curriedFAsAMethod _
- You can un-curry (i.e. go from
A => B => C
to(A, B) => C
) using a standard library method:Function.uncurried
val f: (String, Int) => Double = Function.uncurried(curriedF)
f("a", 1) // => 1.0
Sign up or log in
Save edit as a guest
Join Stack Overflow
We recognize you from another Stack Exchange Network site!
Join and Save Draft