http://t3x.org/mlite/typing.html (light|dark)
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 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 declarations turn constructors, like :node
, into
binary operators (here :node
gets the same precedence as
::
):
infix :node = ::
Infix operators simplify expression syntax a lot:
(:leaf 1 :node :leaf 2) :node (:leaf 3 :node :leaf 4)
Even algebraic types are heterogenous:
(:leaf 1 :node :leaf "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 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.