[MLton-user] Sockets+Monads in SML?

Vesa Karvonen vesa.a.j.k at gmail.com
Fri Feb 15 02:25:21 PST 2008


On Fri, Feb 15, 2008 at 7:02 AM, Wesley W. Terpstra <wesley at terpstra.ca> wrote:
> On Feb 15, 2008, at 1:33 AM, Vesa Karvonen wrote:
[...]
> Well, I was hoping it might somehow be possible to come closer to Haskell's:
>
> do myprint "hello"
>      x <- read
>      y <- read
>      myprint (x ^ y ^ "\n")
>
> I thought someone might know a more elegant style.

I believe there are Haskellers that do not find the do -notation
particularly elegant, because it forces you to give names to
intermediate results.  In an imperative language with a specified
order of evaluation, you could write:

  myprint "hello"
  myprint (read s ^ read s ^ "\n")

However, I wouldn't mind having a do -notation in SML.  Something like this:

  do module_path
   ( expression
   ; pattern <- expression
   ; val pattern = expression
   ; return expression
   )

> When you have 4+ steps and a couple branching cases, the brackets become a
> problem. -- I am not an emacs user.

I wasn't exactly born with Emacs either.  I actually started using
Emacs when I started programming in OCaml.  After an initial
"adjustment period", I've been quite happy using (X)Emacs ever since.
If you don't like Emacs for some really good reason ;-), I'm sure you
can find some other editor that highlights matching parentheses or
patch your editor of choice to do that.  At least, as an Emacs user, I
don't find it much of a burden to match parentheses.

> > > 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.

BTW, I forgot to mention earlier that, as we all know, case
-expressions also allow you to introduce bindings.  I actually use
case -expressions quite frequently in my SML code to just bind a
value, because it is shorter:

  let val x = y in ... end
  case y of x => ...

> Threads are very nice and tempting. However, if you have parallel things to
> execute, threads are actually restrictive. Using the functional callback
> style means you can write things like:
>
> onceAnyFinishIn [ send "x", send "y",  send "z" ] doThis
> onceAllFinishIn ...

I don't immediately see why something like the above couldn't be
achieved with threads.  Above, each "send" would create a thread and
leave it suspended.  Each thread would signal when it is finished.
"onceAnyFinishIn" would enable the threads and wait for a signal from
any of the threads.  After receiving such a signal, it would activate
the "doThis" thread(?).  To make a 'send "x"' into reusable
first-class "actions", they could roughly be thunks (or functions) to
create threads.

> Also, most of these event chains are relatively short lived. Maybe I'm
> wrong, but I think threads would be quite wasteful in this case.

It is possible, but MLton's threads are fairly lightweight and,
considering recent discussions, could perhaps be made even lighter.  I
would at least recommend writing a small benchmark (using both
approaches).

> > Yes, I agree that the required parenthesis are a bit of a nuisance.  I
> > would personally consider changing the syntax of SML to allow fn
> > -expressions without parentheses in these contexts like in Haskell.
>
> I assumed there is some reason the ()s are required..? Maybe to avoid the
> problems nested 'case' statements have?

Yes, there would likely be trade-offs.  I haven't considered the
issues in detail.

> I find the let -syntax fine for functional programming, but somewhat
> verbose for imperative programming (note the "val () =" in the earlier
> example).  I would personally ditch the let -syntax and change the
> syntax of SML's sequence expressions to allow bindings like at the top
> level.  This would make imperative programming more convenient.  The
> thread based version would become:
>
>   fun f x s =
>       (print "hello\n"
>      ; val x = read s
>      ; val y = read s
>      ; print (x ^ y ^ "\n"))
>
> This is one of two things I like about OCaml as compared to SML.

Yeah, OCaml's syntax is somewhat friendlier to imperative programming.
 In OCaml, one could write:

let f x s =
   print_string "hello\n" ;
   let x = read s in
   let y = read s in
   print_string (x ^ y ^ "\n")

I would still prefer the syntax I'm proposing above.  I recall having
problems with OCaml's treatment of semicolons while learning the
language.

> The other is that constructors must be capitalized (so no brackets are needed in
> patterns).

It has been a while since I last took a closer look at OCaml's syntax,
but I don't think the two are related (omission of parentheses and
capitalization of constructors).  OCaml has a special case to avoid
parentheses with tuples and has n-ary constructors with a syntax that
is easily confused with tuples.  I recall having problems with n-ary
constructors more than once while learning OCaml.

-Vesa Karvonen



More information about the MLton-user mailing list