http://t3x.org/mlite/typing.html

[mLite]

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.


contact  |  privacy