1.1 Translating mathematics into code
As we can see from the output above, the function is_prime returns a value of type Boolean. Therefore,
the function is_prime has type
Int => Boolean.
A function that returns a Boolean value is called a predicate.
In Scala, it is optional – but strongly recommended – to specify the return type of named functions.
The required syntax looks like this,
def is_prime(n: Int): Boolean = (2 to n-1).forall(k => n % k != 0)
However, we do not need to specify the type Int for the argument k of the nameless function k =>
n % k != 0. The Scala compiler knows that k is going to iterate over the integer elements of the range
(2 to n-1), which effective ly forces k to be of type
Int.
1.1.3 Nameless functions and bound variables
The code for is_prime differs from the mathematical formula (
1.1) in two ways.
One difference is that the interval [2, n −1] is in front of forall. Another is that the Scala c ode uses
a nameless function (k
=> n % k != 0), while Eq. (1.1) does not seem to involve any functions.
To understand the first d ifference, we need to keep in mind that the Scala syntax such as (2 to
n-1).forall(k => ...) means to apply a function called forall to two arguments: the first argument is
the range (2 to n-1), and the sec ond argument is the nameless function (k
=> ...). In Scala, the infix
syntax x.f(z), or equivalently x f z, means that a function f is applied to its t w o arguments, x and z.
In the ordinary mathematical notation, this would be f (x, z). Infix notation is often e asier to read
and is widely used, e.g. when we write x + y rather than something like plus(x, y ).
A single-argument function could be also defined with infix notation, and then the syntax is x
.f,
as in the expression (1 to n)
.product we ha v e seen before.
The infix methods .product and .forall are already provided in the Scala standard library, so it is
natural to use them. If we want to avoid the infix syntax, we could define a f unction for_all with
two arguments and write code like this,
for_all(2 to n-1, k => n % k != 0)
This would have brought the syntax somewhat closer to
the formula (1.1).
However, there still remains the sec ond difference: The symbol k is used as an argument of a
nameless function (k
=> n % k != 0) in the Scala code, – while the mathematical formula
∀k ∈ [2, n − 1] : n , 0 mod k (1.2)
does not seem to use any functions but defines the symbol k that goes over the range [2, n −1]. The
variable k is then used for writing the predicate n , 0 mod k.
Let us investigate the role of k more closely. The mathematical variab le k is actually defined only
inside the expression “∀k : .. .” and makes no sense outside that expression. This becomes clear by
looking at Eq. (
1.1): The variable k is not present in the left-hand side and could not possibly be
used there. The name “k” is defined only in the right-hand side, where it is first mentioned as the
arbitrary element k ∈ [2, n −1] and then used in the sub- expression “... mod k”.
So, the mathematical notation in Eq. (
1.2) says two things: First, we use the name k for integers
from 2 to n −1. Second, for each of those k we evaluate the expression n , 0 mod k, which can be
viewed as a ce rtain given function of k that returns a
Boolean v alue. Translating the mathematical
notation into code, it is therefore natural to use the nameless function
k 7→ n , 0 mod k
and to write Scala code applying this nameless function to each element of the range [2, n −1] and
checking that all result values be true:
(2 to n-1).forall(k => n % k != 0)
Just as the mathematical notation d efines the variable k
only in the right-hand side of Eq. (1.1), the argument k of
the nameless Scala function k => n % k != 0 is defined only within tha t function’s body and cannot
be used in any code outside the expression n % k != 0.
7