[MLton-user] Sockets+Monads in SML?
Wesley W. Terpstra
wesley at terpstra.ca
Thu Feb 14 11:14:57 PST 2008
I am planning on implementing a fairly large network application in
SML. It's a port of the work done in my thesis. Much of the original
code consists of event handlers connected in sequence. I am looking
for an SML idiom that can express this cleanly.
Haskell has the concept of Monads, which comes quite close to what I
need:
> infix 0 >>=
>
> fun f >>= g = f g
>
> fun myprint str ret = (print str; ret ())
> fun read ret = ret "result"
>
> fun f x =
> myprint "hello\n" >>= fn () =>
> read >>= fn x =>
> read >>= fn y =>
> myprint (x ^ y ^ "\n") >>= fn () =>
> ()
The method 'read' would in reality return from the method, but install
the 'ret' function to be called once the data was ready. The problem
here is that 'fn' can't be used without ()s. Is there any way to
introduce variables without excessive bracketing? It would also be
very helpful if pattern matching were available, eg:
read (socket, Time.fromSeconds 10) >>=
fn TIMEOUT => ...
| DATA x => ...
The problem I'm running up against is that only 'let' clauses and
function declarations can introduce variable scope. AFAICT, the let
clause prevents me from popping out of the method after installing a
signal handler. The function approach suffers due to the syntax of SML.
Does someone have a tidy way of writing code like this?
Also, I am concerned by MLton's closure conversion. With this style of
programming, there are a *lot* of bound variables which pile up
towards the end of the event chain. As I understand it, the closure
of MLton is converted into a datatype which represents the function to
call + it's free variables. The longer these chains of event handlers
get, the more free variables in the later functions. My concern is
that it will cost me a lot to convert these datatypes. I am under the
impression MLton will flatten them out into one record at each step
rather -> O(n^2) cost for n steps of function nesting (if nearly all n
variables are used in the last step, which is quite typical). Should I
be worried?
For comparison, when I program this in C++ I create a class with all
the variables I will need and member methods which handle each step in
the chain. I draw a nice flow chart for all the events and which leads
to whatever, and then carefully manage the lifetime of the object and
at the end of each step hook the 'next' member methods to the event
loop. This is very error prone (missing the an alternative for the
next step, missing cases where the object stays live, killing the
object too soon, unhooking events that weren't hooked, etc). However,
it also doesn't waste a lot of work rebuilding the record. I was
hoping that a functional language like ML would relieve me of needing
such an object (closures = garbage collected) and pattern matching
could help to ensure branch coverage.
More information about the MLton-user
mailing list