Functions

Functions are defined using the keyword fn and must have explicit type annotations.

fn double(x: Int) -> Int {
  x * 2
}

Functions can be called using C-style function calls:

double(42)

Void Functions

Functions that do not return a value can omit the return type instead of explicitly saying Void.

fn ignore<T>(x: T) {
  // evaluates whatever is passed into `x`, but ignores it's result
}

Currying

All the functions are automatically curried, which means that both of the following are equivalent.

fn add(x: Int, y: Int) -> Int {
  x + y
}

fn add(x: Int) -> (Int) -> Int {
  fn add'(y: Int) -> Int {
    x + y
  }
}

Both of the add functions defined above can be called in any of the following ways.

add(3, 5)

add(3)(5)

let add3 = add(3)
add3(5)

Universal Function Call Syntax (UFCS)

UFCS allows you to call a function as if was a method of its first argument. Let’s see an example:

fn bool_to_int(x: Bool) -> Int {
  if x { 1 } else { 0 }
}

bool_to_int(False) //=> 0 : Int

// Alternatively

True.bool_to_int() //=> 1 : Int

This makes it possible to “extend” a class after its definition.

class C { /* ... */ }

let c = C({})

fn printC(self: C) {
  // ...
}

c.printC()

And behaves similar to the reverse application operator in other functional languages like Elm, F# and OCaml (and recently proposed to JavaScript):

list.map(f).filter(g).sort(h).iter(i)

is equivalent to the following in Elm for example:

list |> map f |> filter g |> sort h |> iter i

with the difference that with UFCS the object is passed as the first argument and with the reverse application operator it would be passed as the last argument.