mondrian.runtimeMondrian supports concurrent programming using threads. A MondrianThread object is a subclass of the underlying platform Thread object. This means programs may be a mix of Mondrian and other platform language threads, and these threads may interact with each other. The supplied Dining Philosopher sample program is a concurrent program consists of Mondrian and Java or C# threads.
Threads are created and controlled using monadic functions provided by the MThread object.
Note: The MThread object is the one standard object in Mondrian which has Mondrian-callable methods. In future such objects may be user-definable.
MThread.setup : IO a -> IO (MondrianThread a);
Creates a thread object which evaluates the argument action of type
IO a. Currently there is no way to retrieve the value of typeawhen the thread terminates. As in .NET/JVM the thread is created but not started. The returnedMondrianThreadobject is a platform thread object and can be passed to other languages running on the platform.
MThread.start : MondrianThread a -> IO Void;
MThread.join : MondrianThread a -> IO Void;
MThread.suspend : MondrianThread a -> IO Void;
MThread.resume : MondrianThread a -> IO Void;
MThread.sleep : Integer -> IO Void;
These functions mirror the methods provided on platform threads, but provide them as actions which can be executed within Mondrians
IOmonad.
The evaluation models of Mondrian and standard .NET/JVM platform languages such as C# and Java are fundamentally different. In particular values in Mondrian are not evaluated until needed. From the C#/Java perspective this means fields of Mondrian created objects cannot simply be accessed to obtain their values, as the value may not yet have been evaluated - such an unevaluated value is represented by a special object which encapsulates the computation needed to obtain the value.
Function calling is also different. In Mondrian functions can be applied to fewer arguments than required, the result of such an application is a partially applied function which is just another function which expects the remaining arguments.
Every user defined Mondrian function is represented on the platform as a class with well known methods. One of these methods is Eval and is provided to enable other languages to apply the function (the Mondrian system itself uses a different method not suitable for other languages to call). This method takes the appropriate number of arguments and returns the result of the function in weak head normal form (WHNF). If the type of the result is one of the primitive types (Integer, Character, Boolean. Double, String) then its WHNF is the value. If it is a structured type, e.g. a List, then its WHNF is the first object, e.g. a Cons or a Nil object for a List value, however any fields in the object may not yet have been evaluated.
The mondrian.prelude package provides the following functions:
from : Integer -> List Integer;
drop : Integer -> List a -> List a;
hd : List a -> a;
tl : List a -> List a;
The following is a C# fragment which uses these:
// Create the "infinite list" starting from 10
List myList = from.Apply(10);
// Now myList.head may be 10 or it may be a special object which contains
// a method which when called returns 10 - so we can just access the value, so...
Console.WriteLine("First value is " + hd.Apply(myList));
// Now skip 17 elements. We can't write a loop which walks down myList.tail
// as, you've guessed it, myList.tail may not be a List object - just imagine
// what would happen if it was. As from.Apply(10) has returned the list of all
// integers from 10 and it has been fully constructed then it contains a mere
// 2,147,483,638 objects... This is one reason why Mondrian uses non-strict
// evaluation! We could use a loop which calls tl(), but we'll take the easy
// route and use drop()
myList = drop.Apply(17, myList);
// Finally print out the current head of the list, note we can call a Mondrian
// function object as many times as we want - we don't need a new hd() object.
Console.WriteLine("18th value is " + hd.Apply(myList));
The above works fine as long as we have known function objects. What happens if we have an anonymous function object? Mondrian provides a number of static Eval methods which take a function object and zero, one, two, three, four, or an array of how many you like, argument objects. Using these you can evaluate any Mondrian function/value. If you supply too few arguments you will be returned a partially applied function, which is a function itself, just as in Mondrian. If you supply too many the excess ones are ignored.
The functions in Mondrian are:
public static Object Mondrian.Eval(Object func);
public static Object Mondrian.Eval(Object func, Object arg1);
public static Object Mondrian.Eval(Object func, Object arg1, Object arg2);
public static Object Mondrian.Eval(Object func, Object arg1, Object arg2, Object arg3);
public static Object Mondrian.Eval(Object func, Object arg1, Object arg2, Object arg3, Object arg4);
public static Object Mondrian.Eval(Object func, Object[] args);
Returning to our example above, the 18th value could also have been printed using:
Console.WriteLine("18th value is " + Mondrian.Eval(((Cons)myList).head);
Of course if you do this you should really first check you have a Cons object or you will get a cast exception. (Similarly if you call hd() on a Nil object you will get a PatternMatchingException.)
One of the primes sample programs also demonstrates how to use the Eval methods.
Last modified: