Unlike in most functional programming languages, functions are not first-class citizens in Melodeon. They cannot be passed as arguments into other functions (that is, Melodeon doesn’t have higher-order functions). Instead, they are always defined at the “top level”.

Here’s how to define a function in Melodeon:

def function_name(arg_1: type_1, arg_2: type_2, ..., arg_n: type_n) =

Argument type annotations are mandatory, as explained in the section on type inference. The function body must be a single expression.


def double(x: Nat) = x * 2
def poly(x: Nat) =
    x ** 2 + quadruple(x) + 8

def quadruple(x: Nat) =
    loop 2 do
        x <- x + x
    return x
def to_point(x: Nat, y: Nat) =
    Point{x: x, y: y}

struct Point {
    x: Nat,
    y: Nat

As we see from these examples, the order of definitions does not matter in Melodeon. Furthermore, function and variable names must start with a lower-case letter and are idiomatically written in snake_case.

Optionally, you can annotate the output type, like this:

def double(x: Nat) : Nat = x * 2

def tuplify(x: Nat, y: Nat) : Point =
    Point{x: x, y: y}

Currently, all functions must be defined in .melo files; support for function definitions in the REPL is forthcoming!