Posted by Beetle B. on Sat 30 July 2016

Defining Functions

Look at the following example to declare a function:

fun pow(x:int, y:int) =
  if y = 0
  then 1
  else x * pow(x, y-1)

If your function takes only one argument, you do not need parentheses in the function call. Nothing bad will occur if you do have them, though.


fun functionname (x1:t1, x2:t2, ..., xn:tn) = e

ti is the type of xi.

There is no way to have variable number of arguments.

Type Checking

Type check e in a static environment that currently exists, in addition to mapping x1 to t1 and so on.

functionname will have the type t1 * t2 * ... * tn -> t where t is the type of e.

Note that functionname is added to the static environment prior to evaluation of e, and thus one can recursively call within e.

Also note that the arguments x1, etc are added only to an augmented environment of e. They are not available elsewhere.


The function itself is the evaluation (and not the call to the function).

Function Calls


f0 (e1,...,en)

Type Checking

We require that f0 evaluates to a type of t1 * ... * tn -> t where ti is the type of ei. Then the call has type t.


Each of the ei is evaluated to vi, and those arguments are added to the environment of execution. The environment it is added to is the one that was current when the function was defined, not the one where it is being called.


Functions in Standard ML have lexical scope. This means it uses variables that were active when it was defined - even if the value of the variable is changed later, it will use the earlier value of the variable.

When you create a function, it has two parts:

  • The code
  • The environment at the time of creation

These two together form a closure. This environment is part of the function and remains with the function.