http://t3x.org/mlite/typing.html # The mLite Type System

Types in mLite are bound to values rather than variables, and they are checked dynamically at run time.

Primitive lists are heterogenous:

```[ 1, "hello", #"x", true, 1.61, fn x=x ]
```

## Algebraic Types

Algebraic compound data types can be defined by the user:

```type :tree = :leaf (x) | :node (:tree, :tree)
```

Constructors are used to build complex data structures:

```:node (:node (:leaf 1, :leaf 2)     ;;      o
:node (:leaf 3, :leaf 4))    ;;     / \
;;    /   \
;;   o     o
;;  / \   / \
;; 1   2 3   4
```

Infix declaration turn constructors, like `:node`, into binary operators (here `:node` gets the same precedence as `::`):

```infix :node = ::
```

Infix operators simplify expressions syntax a lot:

```(:leaf 1 :node :leaf 2) :node (:leaf 3 :node :leaf 4)
```

Even algebraic types are heterogenous:

```(:leaf 1 :node "foo") :node (:leaf 3 :node :leaf [1,2,3])
```

However, they check their consistency, e.g. a `:node` accepts only a tuple of `:tree`'s as its argument:

```:node (:leaf 1, "oops")  ;; THIS WON'T WORK, because "oops" is not a :tree
```

## Functions

Functions are polymorphic, with a much greater flexibility than in statically typed languages (at the expense of safety, of course).

For example, the `q` function, below, computes the quotient of two numbers when passed a tuple, and the reciprocal value when passed a singular argument:

```fun q (x, y) = x / y
| x      = 1 / x
```

The `revnum` function reverses a number:

```fun revnum (0, b) = b
| (a, b) = revnum (a div 10, b * 10 + a mod 10)
| a      = revnum (a, 0)
```

When applied to a single argument, it calls itself with a tuple containing an accumulator (b). However, this is a technique that is only useful for ad-hoc hacking, because it allows you to do things like this (giving the unspecified result 98123):

`revnum (123, 98)`

So in production code, `revnum` would look like this:

```local
fun revn (0, b) = b
| (a, b) = revn (a div 10, b * 10 + a mod 10)
in
fun revnum a = revn (a, 0)
end
```

Pattern matching can be combined with guard expressions and type predicates. The following function can be used to compare any combination of characters, strings, or numbers, where a type mismatch results in a `false` result:

```fun equals (a, b) where char a
= char b also a = b
| (a, b) where str a
= str b also a = b
| (a, b) where real a
= real b also a = b
| _ = false
```

However, the built-in `eql` function should be used to do this, because it covers all types of the mLite language.