We have seen Orc's predefined data structures: tuples, lists, and records. Orc also provides the capability for programmers to define their own data structures, using a feature adopted from the ML/Haskell language family called datatypes (also called variants or tagged sums).
Datatypes are defined using the type declaration:
type Tree = Node(_,_,_) | Empty()
This declaration defines two new sites named Node and Empty.
Node takes three arguments, and publishes a tagged value
wrapping those arguments. Empty takes no arguments and does the same.
Once we have created these tagged values, we use a new pattern called a datatype pattern to match them and unwrap the arguments:
type Tree = Node(_,_,_) | Empty() {- Build up a small binary tree -} val l = Node(Empty(), 0, Empty()) val r = Node(Empty(), 2, Empty()) val t = Node(l,1,r) {- And then match it to extract its contents -} t >Node(l,j,r)> l >Node(_,i,_)> r >Node(_,k,_)> ( i | j | k ) {- OUTPUT:PERMUTABLE 0 1 2 -}
One pair of datatypes is so commonly used that it is already predefined in the standard library:
Some(_) and None(). These are used as return values for calls that
need to distinguish between successfully returning a value (Some(v)), and successfully
completing but having no meaningful value to return (None()). For example, a lookup
function might return Some(result) if it found a result, or return None()
if it successfully performed the lookup but found no suitable result.