Live data from Hacker News

Standard ML in 2020

notes.eatonphil.com

81–90 of 125 posts

Re: Standard ML in 2020

#81
post #34

Earlier quoted context omitted.

> Despite this, the language doesn't have the academic flaws of its descendants like Haskell. Can you elaborate on what those flaws are?

The 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 be…

I find there are two main problems with monads in Haskell:

- Monad is just an interface (with nice do-notation, to be sure), but it's elevated to an almost mythic status. This (a) causes Monad to be used in places which would be better without (e.g. we could be more generic, like using Applicative; or more concrete by sticking to IO or Maybe, etc.) and (b) puts off new comers to the language, thinking they need to learn category theory or whatever. For this reason, I try to avoid phrases like "the IO monad" or "the Maybe monad" unless I'm specifically talking about their monadic join operation (just like I wouldn't talk about "the List monad" when discussing, say, string splitting)

- They don't compose. Monad on its own is a nice little abstraction, but it forces a tradeoff between narrowing down the scope of effects (e.g. with specific types like 'Stdin a', 'Stdout a', 'InEnv a', 'GenRec a', 'WithClock a', 'Random a', etc.) and avoiding the complexity of plugging all of those together. The listed advantages of SML are essentially one end of this spectrum: avoiding the complexity by ignoring the scope of effects; similar to sticking with the 'IO a' type in Haskell (although even there, it's nice that Haskell lets us distinguish between pure functions and effectful actions).

Haskell has some standard solutions to composing narrowly-scoped effects, like mtl, but I find them to be a complicated workaround to a self-imposed problem, rather than anything elegant. I still hold out some hope that algebraic effect systems can avoid this tradeoff, but retro-fitting them into a language can bring back the complexity they're supposed to avoid (e.g. I've really enjoyed using Haskell's polysemy library, but it requires a bunch of boilerplate, restrictions on variable names and TemplateHaskell shenanigans to work nicely).

Re: Standard ML in 2020

#82
post #22

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 soun…

Have you used CML for any real projects? Very curious to see. I've always used Poly/ML when I wanted parallelism.

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

Re: Standard ML in 2020

#83
post #22

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 soun…

How does it compare to OCaml?

OCaml's design was influenced by Standard ML

Re: Standard ML in 2020

#84
My favourite thing about SML is that it's a relatively idiot-proof language. It has something of Python's "one obvious way to do it" - a good chance of being able to understand someone else's code. This is partly because the language is small and features many sensible decisions, and partly because it isn't particularly malleable at the syntactic level (compared to your Lisps or Haskell).

The tradeoff is that it can be more laborious than other functional languages. My code would be shorter if it had record updating, a single-character lambda syntax, contextual operators for real or int arithmetic, etc. Not only does it lack syntactic sugar for associative containers, it doesn't even have them in the standard library. Nor sorting, nor random numbers, nor complex numbers or matrices, nor uniform type-to-string formatting or string interpolation. Some of these holes can be filled by libraries, but then library choice becomes a problem.

I can live with an awful lot of that though, given the relative clarity of the language, the really practical module system, and the delightful feeling you get when using a language standardised over 20 years ago that, once written, your code can stay written.

Re: Standard ML in 2020

#85
post #78
post #58

Earlier quoted context omitted.

I 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, bu…

As a bit of an aside, it's interesting that the CS (Haskell, mainly) descriptions of a Monad are much more complicated than the math. Knowing a little bit of maths, but not much category theory, the wiki entry for Monads(Category Theory) is pretty clear. First sentence: A Monad is an endofunctor (a functor mapping a category to itself), together with two natural transformations required to fulfill certain coherence c…

> Easy.

The formal definitions are straightforward enough, but the definitions alone don't really motivate themselves. A lot of mathematical maturity is about recognizing that a good definition gives a lot more than is immediately apparent. Someone without that experience will want to fully understand the definition, and fairly so -- but a plain reading defies that understanding. That is objectively frustrating.

> As a bit of an aside, it's interesting that the CS (Haskell, mainly) descriptions of a Monad are much more complicated than the math.

I actually do agree with this, though. I feel like monads are much simpler when presented via "join" (aka "flatten") rather than "bind"; and likewise with applicative functors via monoidal product (which I call "par") rather than "ap". "bind" and "ap" are really compounds of "join" and "par" with the underlying functorial "map". That makes them syntactically convenient, but pedagogically they're a bit of a nightmare. It's a lot easier to think about a structural change than applying some arbitrary computation.

Let's assume the reader knows abut "map". Examples abound; it's really not hard to find a huge number of functors in the wild, even in imperative programs. In short, "map" lets us take one value to another, within some context.

Applicative functors let us take two values, `f a` and `f b`, and produce a single `f (a, b)`. In other words, if we have two values in separate contexts (of the same kind), we can merge them together if the context is applicative.

Monads let us take a value `f (f a)` and produce an `f a`. In other words, if we have a value in a context in a context, we can merge the two contexts together.

Applicative "ap", `f (a -> b) -> f a -> f b`, is "par" followed by "map". We merge `(f (a -> b), f a)` to get `f (a -> b, a)`, then map over the pair and apply the function to its argument.

Monadic "bind", `(a -> f b) -> f a -> f b`, is "map" followed by "flatten". We map the given function over `f a` to get an `f (f b)`, then flatten to get our final `f b`.

It's a lot easier to think about these things when you don't have a higher-order function argument being thrown around.

Re: Standard ML in 2020

#86
post #60

I am designing a language based on OCaml/Standard ML, what are some of the problems present in these languages that can be fixed by a new design without being constrained by a spec or backwards compatibility?

Use utf8 strings, not utf32. It's the standard in most new languages for good reasons.

Have a standard iterator type. Syntax wise, something closer to rust would help newcomers (see ReasonML maybe).

Re: Standard ML in 2020

#87
post #60

I am designing a language based on OCaml/Standard ML, what are some of the problems present in these languages that can be fixed by a new design without being constrained by a spec or backwards compatibility?

  - you want `deriving`
  - you might want to look at staging (MetaOCaml)
  - you might want to look at resource management (uniqueness typing fe)
  - you might want to look at paralellism and maybe you can even release it before Ocaml/multicore arrives ;)

Re: Standard ML in 2020

#88
post #22

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 soun…

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

Re: Standard ML in 2020

#89
post #35

Earlier quoted context omitted.

SML records are structurally typed and may be anonymous which makes a lot of things easier to write. I've heard Ocaml has been attempting to tack that on, but that leads to the next point of Ocaml syntax being a complete mess. Ocaml needs keyword arguments, but in SML, structural typing gives named arguments without all the extra syntax. I find the `ref` syntax of SML much nicer to use than the mutable record syntax…

> Module Typeclasses should keep typeclasses from happening everywhere (looking at you Haskell) while still allowing them to be used for more than equality. I was under impression that Haskell's typeclasses plus a couple of most common extensions minus the namespace pollution are pretty much equivalent to ML modules+functors, so could you elaborate how exactly that should work?

Yes and no. They can do the same thing, but with varying amounts of effort. SML has what is essentially a hard coded typeclass for equality with special syntax for it as well (two single quotes instead of one). There can also be issues creating and overloading operators. There's still ongoing discussion about modular typeclasses for SuccessorML

Here's some info if you're interested.

https://www.cs.cmu.edu/~rwh/papers/mtc/short.pdf

Re: Standard ML in 2020

#90
post #22

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 soun…

How does it compare to OCaml?

They'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.).

Post reply on HN