mLite Expression Syntax

The mLite language is mostly based upon expression evaluation. Expressions are composed of function application, infix operators, and some additional, more specialized constructs.

Like in ML, function application is expressed by juxtaposition (a --> b means "a evaluates to b"):

sqrt 2          -->  1.414213562373095
gcd (12,8)      -->  4
map (fn x=2^x)  -->  fn a

Note that you will have to type a semicolon to make the mLite interpreter evaluate an expression!

Function applications associates to the left, so

map (fn x = 2^x) [1, 2, 3, 4, 5]

would in fact be

(map (fn x = 2^x)) [1, 2, 3, 4, 5]

which is quite convenient, because it first applies map to the function fn x=2^x, giving a new function, and then applies that function to the list:

map (fn x = 2^x)               -->  fn a
map (fn x = 2^x) [2,3,5,7,11]  -->  [4, 8, 32, 128, 2048]

Right-to-left Application

In other circumstances, left-to-right evaluation makes less sense, though. For instance

println rev iota 100

should really be

println (rev (iota 100))

but this is ugly due to all of the extra parentheses. This is why the "apply" operator (`) exists:

println ` rev ` iota 100

The backtick in mLite is basically the same as the dollar operator in Haskell. It evaluates the left- and righthand side and then applies the left side to the right one.

Also note that, like in ML, function application binds stronger than infix operations so, for instance,

f x + g y

actually means

(f x) + (g y)

If something else is intended, the apply operator can help even here:

f ` x + g y

would mean

f (x + (g y))


Currying is present in the mLite language, but not used as frequently as in the ML language, mostly because it cannot be combined with alternative patterns (i.e. the | operator). Functions use tuples instead of currying for multiple arguments. e.g.:

fun power2 (x, 0) = 1
         | (x, y) = power2 (x, y - 1)

However, a curried version of the function can easily be created:

fun power a b = power2 (a, b)

As in ML, this is equal to

fun power a = fn b = power2 (a, b)

In a typical higher-order function, a staged function using tuples would be used internally and a function using the staged function would be returned. The below zipwith function incidentally returns a curried function, because it expects three arguments.

fun zipwith f = let fun zip (a, [], r) = rev r
                          | ([], b, r) = rev r
                          | (a :: as, b :: bs, r)
                                       = zip (as, bs, f (a, b) :: r)
                in fn a b = zip (a, b, [])

This is actually the one area where mLite is currently less flexible than ML, because its compiler currently cannot rewrite cases using common patterns.