• No categories


Whiley provides record types (similar to those found in [[JavaScript]]) for hierarchically structured data (a.k.a. algebraic data types). The following illustrates the main idea:

void ::main(System.Console console):
    p = {x:1, y:1}
    z = p.x

Here, we see variable p has a record type with two fields, x and y, which can be accessed using the “.” operator.  Generally speaking, it’s more elegant to use the define operator, like so:

// parser state
define state as { string input, int pos }

// parse whitespace!
state parseWhiteSpace(state st):
  while st.pos < |input| && st.input[st.pos] == ' ':
    st.pos = st.pos + 1
  return st

We can also define record types recursively, which is important for creating composite data-structures.

define tree as {tree lhs, tree rhs} | int

void ::main(System.Console console):
    tree t2 = 1
    tree t2 = {lhs: t1, rhs: 2}

This example shows several features: firstly, tree is a recursively defined data type which corresponds to some kind of binary tree; secondly, the choice operator “|” defines a data type whose variables can take on either type (a.k.a. union types). In such a situation, we can use the is operator (similar to Java’s instanceof) to distinguish the actual type of a variable:

int eval(tree x):
    if x is int:
        // type of x now int
        return x
        // type of x now { tree lhs, tree rhs }
        return eval(x.lhs) + eval(x.rhs)

We can see here another useful feature offered by Whiley: flow-sensitive types.  This means the type of a variable can vary at different points within a function.  In the above example, the type of x is adjusted accordingly when x is int is known to be true and, similarly, when it is known to be false.