
A Tour of Standard ML - saityi
https://saityi.github.io/sml-tour/tour/00-00-welcome.html
======
danielrk
I love Standard ML. As an undergrad, I wrote a compiler in it (through Zhong
Shao's course at Yale), and it remains the most fun I've had using a
programming language, let alone a functional programming language. The syntax
is so simple yet it is extremely expressive. Hindley-Milner types are great,
and the pattern matching is slick. SML also strikes a logical balance between
purity and practicality.

------
vslira
Dan Grossman's "Programming Languages, Part A" (In Coursera) made me fall in
love with SML. Highly recommended.

~~~
platz
This course finally made me understand the WHY of FP. Comparing and
Contrasting the major programming paradigms at a high level, but also actually
writing code was a great combination. Before that I just thought it was only
used for people doing math and finance (which wasn't even close to right, lol)

SML is kind of like the lisp of FP. It's just the minimal core of parametric
polymorphism and hindley-milner type inference, so as a beginner you don't
spend thought cycles language-specific features (that would make it more
useful as a general purpose language) - you just learn and understand the core
concepts and techniques (such as building intuition for how to replace
different kinds of loops with recursion and pattern matching) that will apply
to all FP/HM languages.

~~~
dragonwriter
> SML is kind of like the lisp of FP.

Lisp is the Lisp of FP.

SML is more the SML of FP. Alternatively, SML can be viewed as the Lisp of
_statically-typed_ FP, in that, loosely, SML : Static FP :: Lisp : DynamicFP

~~~
gpderetta
Scheme is the lisp of FP. My understanding is that idiomatic lisp is quite
imperative.

~~~
wirrbel
So is scheme quite often. It appears functional looking at idiomatic scheme
code relying on tail-recursive programming for loops, it appears
procedural/imperative if you look at all the mutation used in scheme code (fun
fact: the Scheme standards R*RS do not speak of functions but of procedures).
Higher-order functions aren't used all that much in many scheme code bases
which is odd from the perspective of a Haskell dev.

~~~
gpderetta
Thanks for the info. My knowledge of the lisp family is quite limited outside
of emacs lisp (which usually has a quite imperative feeling).

------
eatonphil
If you'd like to see more Standard ML, there's a small community on Reddit.

[https://www.reddit.com/r/sml/](https://www.reddit.com/r/sml/)

------
tom_mellior
At [https://saityi.github.io/sml-
tour/tour/02-05-recursion.html](https://saityi.github.io/sml-
tour/tour/02-05-recursion.html) the claim that "This is safe [...]; it will
not explode the stack" is fishy. The function as written is not
"syntactically" tail-recursive. A sufficiently heroic compiler could rewrite
this example into a tail-recursive accumulator-based one, but is that really
required by the specification and commonly implemented in ML compilers?

~~~
saityi
You are correct, and I will fix it. The goal here was to encourage recursion
and assuage fears of recursion coming from other languages: if I remember
correctly, Standard ML does define semantics around 'expansive expressions'
which make them /safer/ than I think most imperative programmers (my targeted
audience) would expect, but this particular example would throw an exception.

To fix it, I will rewrite this section to say that the standard requires
optimising /tail-recursive/ calls away, and modify the example to be
iteratively recursive, but I'd still like to assuage fears of recursion in the
tour. The 'while' loop in SML is actually just a derived form, and is
rewritten to recursion; there is no looping in the language. Do you have any
suggestions for rewording?

This is a work in progress that I was looking for feedback on :) Thank you! If
you see anything else fishy, please let me know.

~~~
tom_mellior
Thanks for your answer! I don't have any specific wording suggestions. If
you're willing to add a specific section on tail recursion, I think you might
leave this example in place (with the first paragraph of the current text) and
then show a tail-recursive version in the next step (with a slightly modified
version of the second paragraph of the current text).

------
cmrdporcupine
Ocaml seems to get more buzz, but about 20 years ago I tried my hand at both
OCaml and SML/NJ and found that I actually far preferred the latter. SML is a
very nice, consistent, and practical language.

Here's a pretty thorough comparison of the two
[http://adam.chlipala.net/mlcomp/](http://adam.chlipala.net/mlcomp/)

~~~
mhd
Today's there's also F#, which is the "" to Ocaml's ";;" and to SML's ";".

Concurrent ML is definitely worth looking at.

~~~
bjoli
ConcurrentML has a outgrown its name. It is available in many different
languages. I recall hearing Mike Sperber saying that his company usually just
re-implemened it in whatever language they happened to work in that week.

It is a really nice system that is similar to go, but the primitives it gives
you are in a way a generalisation of go's concurrency primitives.

~~~
throwaway17_17
Can you point me in the direction of any reading on this, I’d be interested to
hear about it.

~~~
the_why_of_y
The canonical source is John Reppy's book:

[https://www.goodreads.com/book/show/302685.Concurrent_Progra...](https://www.goodreads.com/book/show/302685.Concurrent_Programming_in_ML)

Intro article:

[https://medium.com/@asolove/synchronizable-abstractions-
for-...](https://medium.com/@asolove/synchronizable-abstractions-for-
understandable-concurrency-64ae57cd61d1)

There's an interesting series of blogs by Andy Wingo on comparing CML with Go
and implementing it in Guile Scheme:

[https://wingolog.org/archives/2016/09/20/concurrent-ml-
versu...](https://wingolog.org/archives/2016/09/20/concurrent-ml-versus-go)
[https://wingolog.org/archives/2016/09/21/is-go-an-
acceptable...](https://wingolog.org/archives/2016/09/21/is-go-an-acceptable-
cml) [https://wingolog.org/archives/2016/10/12/an-incomplete-
histo...](https://wingolog.org/archives/2016/10/12/an-incomplete-history-of-
language-facilities-for-concurrency)
[https://wingolog.org/archives/2017/06/29/a-new-concurrent-
ml](https://wingolog.org/archives/2017/06/29/a-new-concurrent-ml)

------
cannam
This is neat, and I didn't spot any mistakes in my first very light skim
through.

One practical nit is that the position of the "forward" button moves around
depending on how long the section title is, so you have to keep chasing it.
Possibly it could move to the left of the section title, so back and forward
buttons are clustered together in a fixed place?

~~~
saityi
Yep! I will get that fixed. Thank you for the feedback!

If you find anything else, issues and feedback are also welcome on the issue
tracking @ [https://github.com/Saityi/a-tour-of-standard-
ml/issues](https://github.com/Saityi/a-tour-of-standard-ml/issues) \-- I'm
primarily a backend engineer, and this is my first foray into frontend; even
nitpicks like this are very welcome. :)

------
donpdonp
Very clearly written, easy to consume, easy to navigate. Thank you for this!

~~~
saityi
Thank you for checking it out!

------
platz
Does anyone know how fast MLton (whole-program optimization) programs run in
comparison to other languages?

~~~
tsuyoshi
When I converted a CPU-intensive program from OCaml to MLton-compiled SML,
without changing any of the algorithms, I got a 30% speedup. That was more
than 10 years ago though, and both compilers have seen some improvement since.

~~~
c-cube
OCaml now has flambda, which is a significant improvement on its baseline
optimizer. I think the difference wouldn't be that wide today :)

------
dmix
The automatic currying of functions is awesome, even if the declaration syntax
would take some time to get used to, although it's quite similar to the new JS
anonymous fn declaration (x => x + 1), or maybe the inspiration is reversed.

I had the same problem getting used to Nim with it's Pascal inspired syntax.
But being different is rarely a bad thing as long as it works.

~~~
madhadron
> it's quite similar to the new JS anonymous fn declaration (x => x + 1), or
> maybe the inspiration is reversed.

Yup, that family of syntax descends from Standard ML.

------
plinkplonk
SML is a great language, but the tooling around it wasn't so hot the last time
I checked (admittedly more than a decade ago. With a medium sized ( a few ten
thousand lines) project I had weird build errors and in the end wrote a
makefile. Not fun).

------
hajile
To this day, I don't understand why Google made Go instead of working off of
SML. While the go ecosystem is better due to the millions of man-hours poured
into it, the language is inferior in every way.

To elaborate, CML is better than golang's channels and isn't broken (requiring
mutexes over channels to avoid breaking qualifies as broken). SML syntax is
simpler to learn, but still offers much more powerful abstractions with
pattern matching. SML uses options instead of null pointer exceptions.
Hindley-Milner types are clearly superior to Golang's type system (especially
things like empty interface). SML has had generics for almost 25 years now
while go languishes. SML has immutable data structures and they are the
default for almost everything. Golang has implicit types, but SML's implicit
types are much better -- especially structurally-typed records. SML's modules
are amazing and simply have no comparison in go. Finally, SuccessorML is doing
work toward adding a few new features to the language (for example, module
type classes), but the language has an actual specification that anyone can
implement (and many have) rather than the implementation effectively being the
spec.

~~~
zelly
PL theoretic superiority was not the design goal. Golang was intended to be a
pragmatic, bread-and-butter language for large teams with churn. Bad code
needs to be screamingly obvious. It also needs to be very easy to learn. FP
langs can never fill this role because it's fundamentally more difficult to
think in FP terms than imperative terms. Maybe for small internal projects.
(But if it's successful, it'll get rewritten in Go/Java/C++; people simply
can't handle FP.)

~~~
saityi
'A Tour of Go' inspired this. The format and some of the material come from
there. I think it ended up shorter than the Go tour, and I was hoping it would
be very easy to learn Standard ML from it, as I do consider it to be very easy
to learn. You can pull up the CML examples next to the Go ones, and other than
syntax, they should be the same:

[https://tour.golang.org/concurrency/1](https://tour.golang.org/concurrency/1)

[https://saityi.github.io/sml-
tour/tour/03-01-spawn.html](https://saityi.github.io/sml-
tour/tour/03-01-spawn.html)

There are differences, but once you get to that point in either tour, the
differences shouldn't make it hard to read; if it is hard to read or
understand, that would be welcome feedback, as I have failed in my attempt to
present Standard ML well. :)

(I originally posted this as a 'Show HN', hoping for feedback, so it is
totally welcome.)

~~~
zelly
It is very readable. Helped me get over my initial prejudice after I actually
looked at it.

~~~
saityi
Thanks for checking it out! :)

