Functions

For defining a function, you may use similar syntax known from other languages, such as Scala:

def fib(n: Int): Int =
  if (n == 0 || n == 1) 1
  else fib(n - 1) + fib(n - 2)

Since fib is a recursive function, you need to explicitly annotate its return type. Parameters like n always need to be annotated with their type.

Calling functions works as you might expect:

fib(5)

Perhaps unusual, you can also call fib using Effekt’s implementation of Uniform Function Call Syntax :

5.fib()

Here, the receiver (before the .) is simply passed as the first argument to the function fib. If there are no additional arguments, you can also omit the parenthesis:

5.fib.show.println

To define a type polymorphic (generic) function, like the identity function, you need to introduce a type parameter enclosed in square brackets:

def identity[A](x: A): A = x
val a = identity(42)
val b = identity[Int](42)

When calling the function, you may explicitly pass a type argument for each type parameter or let type inference do its job.

There are also nested function definitions. Thus, we also could have defined fib like this:

def fibNested(n: Int): Int = {
  def inner(last: Int, current: Int, count: Int): Int =
    if (count == 1) current
    else inner(current, last + current, count - 1)

  inner(0, 1, n)
}
fibNested(5)

Only at the top level functions can be mutually recursive.

def even(n: Int): Bool = if (n <= 0) true else odd(n - 1)
def odd(n: Int): Bool = if (n <= 0) false else even(n - 1)
7.even