[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