6 ms·
StandardML really hits a nice sweet spot in language design. The syntax is super-easy to learn (The BNF for the whole fits in a mere 2 pages[0]), but contains
by hajile 6y ago
StandardML really hits a nice sweet spot in language design.
The syntax is super-easy to learn (The BNF for the whole fits in a mere 2 pages[0]), but contains a lot of features in that small package. Rather than tacking on functional features (eg, Java with lambdas), these features have been carefully considered and streamlined and include bits like proper tail calls and currying.
You get nice bits like actually sound types (hindley-milner types as Milner was also one of the SML spec authors), generics (way better than typical interfaces), type inference that actually works, and modules (super-powerful encapsulation). Pattern matching in all it's awesomeness is also on display.
SML has an amazing concurrency story (CML is rather like golang channels, but better with better typing and a bit more flexibility) and compilers like PolyML or Mlton are very fast (once again, around the same as golang).
Despite this, the language doesn't have the academic flaws of its descendants like Haskell.
SML isn't a lazy language, so reasoning about performance is much easier than some other functional languages.
SML doesn't pretend the world is a pure function. You are free to make functions that have side effects.
While most primitives and data structures are immutable by default, they either have mutable variants (eg, vector and array) or can be used as if mutable with refs (something like typesafe pointers without all the reference/dereference bits).
[0] https://cse.buffalo.edu/~regan/cse305/MLBNF.pdf https://cse.buffalo.edu/~regan/cse305/MLBNF.pdf
- eatonphil 6y agoHave you used CML for any real projects? Very curious to see. I've always used Poly/ML when I wanted parallelism.
- bjoli 6y agoOf you are a lisp person guile has a parallel CML implementation called guile-fibers. I used it, just for fun, in a static site generator. That was fun and worked great.
- skissane 6y ago> Despite this, the language doesn't have the academic flaws of its descendants like Haskell. Can you elaborate on what those flaws are?
- dan-robertson 6y agoReasoning about haskell performance is hard because it is a lazy language and the compiler pulls a lot of tricks. In SML, code is executed in some sense roughly in the order it is written whereas in haskell it is very hard to know when something will be executed.
- djhaskin987 6y agoIn Haskell's defense, they meant to do that.
- stutonk 6y agoThe profusion of Category-theoric abstractions and some of the more recent purely functional norms in Haskell are like the PhD-level version of `AbstractVisitorContextFactoryBuilder` which, aside from all the unnecessary cognitive load, lead to enormous dependency graphs of the npm variety. Personally, I wonder if uniqueness types in languages like the sadly forgotten Clean (a close relative of Haskell) would have been better than the whole Monad/Arrow thing. All of that abstract theoretical stuff is certainly fascinating but it's never seemed worth all the bother to me. On the other hand, in SML you get all the benefits of strong HM type inference/checking, immutability by default, etc, etc.. while also still being able to just `print` something or modify arrays in place. SML's type system isn't higher-order like Haskell's so its solution to the same problem Haskell solves with type classes isn't quite as elegant but otherwise SML is the C to Haskell's C++.
- nine_k 6y agoI don't think there's a way to not use monads, because a ton of everyday things just work in a monadic way, things like lists, or statement sequences in presence of exceptions. I think it's wiser to admit and use these properties instead of ignoring them. Ignoring maths that underlie computation when writing software is like ignoring math that underlies mechanics when building houses: for some time you can get by, but bigger houses will tend to constantly fall or stand a bit askew, and the first woodpecker to fly by would ruin the civilization, just as the saying goes. Uniqueness types were a nice idea indeed. I suspect linear types (or their derivative in Rust) do a very similar thing: data are shared XOR mutable.
- nicoburns 6y agoHow does it compare to OCaml?
- Davidbrcz 6y agoOCaml's design was influenced by Standard ML
- wtetzner 6y agoThey're very similar. Some people prefer Standard ML's syntax, though I actually prefer OCaml's (most likely just a result of me learning OCaml first). The module systems have some small differences, but are very similar (I believe OCaml's was inspired by SML's). Standard ML is also standardized (hence the name), and there are multiple implementations, whereas OCaml is basically defined by its single implementation. But OCaml does have a larger ecosystem, Opam, more features (first-class modules, polymorphic variants, etc.).
- jberryman 6y ago> doesn't pretend the world is a pure function. At a first approximation, Haskell pretends the world is a piece of state, not a pure function.
- marcosdumay 6y agoTo be a bit pedantic (because this thing is interesting), it's more like a context. In Haskell you'll say "this code must run on the real world". Mercury literally pretends the world is a piece of state. You explicitly say "Here, run this code. The world before it runs is on variable `a`, place the world after it runs on variable `b`".
- fanf2 6y agoThe classic paper Imperative Functional Programming https://www.microsoft.com/en-us/research/publication/imperative-functional-programming/ https://www.microsoft.com/en-us/research/publication/imperat... introduced the IO monad and explained that its internals are based on passing around the state of the world. The monad hides the world and keeps it linear. The compiler (ghc) optimizes out the world so that it is implicit in the compiled program. I believe this is still the way that ghc works.
- marcosdumay 6y agoOh, yes, the stdlib does pretend the world is a piece of data. But it does a very good job on keeping this hidden from any developer, so this is more of a compiler design that does not leak into the language.
- fouric 6y agoWhy should I use SML over Rust or Lisp? Rust's performance is almost certainly much better, with a larger library ecosystem. (Common) Lisp has macros, which allow me to implement pattern-matching; an even simpler BNF (as short as one line, depending on how you define it); dynamic typing, which makes generics unnecessary, and for all the hate that it receives is regularly deployed to production systems on large scales; tooling that is almost certainly better than SML's; and a condition system, which beats any other type of error-handling system, bar none (meaning that I can make my programs more robust than yours).
- johnnycerberus 6y agoSML over lisp: * Doesn't have macros, which in my 16 years of experience is a plus, macros pollute, should at most be an implementation detail * Has types * Doesn't have parantheses and the annoying prefix notation * Your knowledge of SML can be translated easily to OCaml, Java, Scala, which are more or less part of the same family SML over Rust: * I don't have to reason about lifetimes, I'm not in a constrained environment * TCO (tail call optimization) * At its core, Rust is still an imperative language, it was influenced by ML but not that much as many believe SML over Scala: * It doesn't suffer of Haskellism and Extreme Bipolarity (oop/fp) and gets the job done.
- fouric 6y ago> * Doesn't have macros > * Has types Your words betray your ignorance. Common Lisp has a type system. Have you ever written it? Do you actually know anything about it? Moreover, macros are a plus - you clearly have not actually used Lisp macros, which are categorically different than macros in other languages. > * Doesn't have parantheses and the annoying prefix notation Spelling mistake. Additionally, the parenthesized syntax is a choice, and one that you get used to quickly. Subjective, and therefore not valid as one of the items you listed. > * Your knowledge of SML can be translated easily to OCaml, Java, Scala, which are more or less part of the same family Meanwhile, knowledge of Common Lisp transfers to almost every dynamically-typed language ever made, and a good many static ones - including Java and Scala - because Lisp influenced all of those languages. That is, Lisp knowledge transfers to far more languages than SML knowledge does.