[HN Gopher] What was wrong with SML? ___________________________________________________________________ What was wrong with SML? Author : rdpintqogeogsaa Score : 63 points Date : 2022-04-30 18:10 UTC (4 hours ago) (HTM) web link (blog.plover.com) (TXT) w3m dump (blog.plover.com) | eatonphil wrote: | I mentioned to Mark when I saw this, and he noted it in the | addendum at the end, that calling Standard ML dead is a bit too | much. I've written recently [0] about how active it surprisingly | is. | | I also disagree that its failure to "succeed" has anything to do | with syntax or semantics and solely that it doesn't have a Jane | Street or any company publicly behind it. | | [0] https://notes.eatonphil.com/standard-ml-in-2020.html | porcoda wrote: | I don't think it succeeded or failed. Languages don't need to | be wildly popular in industry to be valuable. I personally like | that industry ignores SML. Even for Ocaml I don't use the Jane | street core: I just use the stock language since it's small and | stable. I like that Jane street helps improve the core compiler | though. | mjd wrote: | I would like to point out that the article does not use the | words "succeed" or "fail", and makes no claim about whether SML | "succeeded" or "failed". Indeed I don't think that is a useful | question to ask. | | My article was trying to address a much less nebulous issue: | what problems did I personally see with SML in the mid 1990s | that let me to abandon it at that time. | eatonphil wrote: | Sorry, I didn't mean to put words in your mouth. I may just | have gotten the wrong impression of your intent. | | Any criticism of any language is valid and good to have! | fanf2 wrote: | There was a history of Standard ML published as part of HOPL4 a | couple of years ago - https://dl.acm.org/doi/10.1145/3386336 I | was particularly interested by the more recent history, after SML | '97, where there was plenty of interest in improving the language | and its library, but Milner insisted that there would be no | further changes, and the Definition was non-free so the others | could not build on it. (It has since become Free though its | source code was lost.) | | Despite that there is/was an SML Basis Library project, and a | Successor ML project, but it looks like even the die hard fans | have drifted away https://smlfamily.github.io/ | bzxcvbn wrote: | I'm not really convinced by the author's first example. While an | element of type bool is an instance of type a, an element of type | bool -> bool is _not_ an instance of type a - > a. | | The issue is precisely an issue of variance, which is mentioned | in reference to Scala, but somehow it's glossed over. The type a | -> a is covariant in its second argument, but contravariant in | its first argument. As a result, you cannot "specialize" it to | bool -> bool, because specialization is really another name for | covariance. | | Another name for contravariance is "generalization". If you ask | for something of type "bool -> b", and someone provides you with | some function f of type "a -> b", then you're happy. The map f is | indeed an instance of "bool -> b": it can eat anything, so it can | eat booleans. But with type a -> a, you cannot do what I just | did: type "a" is already the most general one, and you cannot do | better. | | If SML accepted something of type "bool -> bool" for an instance | of type "a -> a", then it was a fundamental error. But this | doesn't mean that the whole thing should have been thrown out and | replaced with monads. In fact, I don't really get how monads have | anything to do with the problem at hand. If Haskell can prevent | the following code, then I don't see why SML couldn't have | prevented the authors' code: do m <- STRef id | m <- not m 42 | pjmlp wrote: | What was wrong is not having a killer application or an industry | giant pushing it. | | Grammar and language semantic are details regarding language | adoption. | eatonphil wrote: | Yup, adoption has nothing to do with being a sensible language. | More often it seems to be completely inversely related. | exikyut wrote: | What are some sensible (coherent, load-bearing, force- | multiplying etc) tools that have terrible adoption? | | Unreasonably open-ended question (suppose the scope is ML, or | perhaps FP in general, or maybe even wider) - but I'm very | curious. | pharmakom wrote: | I would say F#. It has most things you could want: | | - Proper functional programming support | | - Fast enough runtime | | - Cross-platform and open-source | | - Mainstream ecosystem | | - Large corporate backer | | - Compile to JS | | - Commercial and open-source tooling options | | ... and yet C# is far more popular. This is because | language adoption is driven by existing user base and other | network effects NOT the quality of the language itself. | youerbt wrote: | TLA+ or Nix comes to mind. By some notion of terrible I | guess. | eatonphil wrote: | Google "worse is better". :) | Athas wrote: | > Haskell's primary solution to this is to burn it all to the | ground. Mutation doesn't cause any type problems because there | isn't any. | | This is true, but I think it is also misleading. Haskell has the | same problem if you use unsafePerformIO to create a polymorphic | IORef at top level. You can then use this IORef to subvert the | type system. I think this is something many Haskell programmers | are not fully aware of: unsafePerformIO doesn't just break | referential transparency; it can also fundamentally break memory | safety. Now, you may say that unsafePerformIO is obviously unsafe | (it's in the name!) and should never be used. But if you look at | many foundational Haskell libraries, you will find that they use | unsafePerformIO or similar functions internally, usually for | performance reasons. What are the rules that govern safe usage of | unsafePerformIO? As far as I can determine, these rules are | basically just GHC implementation details, and people often get | them wrong. And if you break these rules, you don't just get a | function that doesn't do what you expected - you may have | subverted memory safety entirely. | | I think this is an interesting conundrum. Haskell makes much | stronger promises than SML, but if you break the rules, all bets | are completely off. | throwamon wrote: | A bit off-topic, but could someone ELI5 what a lattice is in this | context? | mjd wrote: | If you have two types, there should be a single type that | "joins" them, in the sense that you can understand both of the | original types as somehow being special cases of the join type. | | A join is not necessarily a union, since the representations of | the three types might be completely different, and also because | the third type might contain many values that don't correspond | to anything in the two original types. (It might be much bigger | than the union.) | | Mathematical lattices must also have "meets", which are like | joins except down instead of up. I'm not sure that meets are as | important as joins in this context. | layer8 wrote: | It refers to https://en.m.wikipedia.org/wiki/Lattice_(order), | with the elements of the lattice being the arithmetic types and | the order relation being the subtyping relation here. Given any | two types in the lattice, the lattice property then guarantees | that there exists a unique common (least) supertype (aka upper | bound, supremum) of the two types. Which means you can apply | the binary operation (e.g. addition) as defined for that common | supertype. | chombier wrote: | I think this refers to a system of types in which for any two | types there is also an union type and an intersection type in | the lattice. | tialaramex wrote: | SML was the First Language used for the Computer Science degree I | took. I felt at that time, and continue to feel years later (that | degree course now teaches Java as First Language) that this was a | good decision _despite_ the fact that most graduates don 't end | up using SML to write anything. | | In the course of my education I experienced some things which I'm | convinced are a _bad idea_ even though they worked out OK for me | such as selective education (whole schools only for "talented" | children) and single sex secondary education, but SML as First | Language is not one of those things. It worked well for me _and_ | I 'm convinced it's a good idea even though I would not advocate | writing new real world projects in SML unless you've got some | very particular reason. | chombier wrote: | > Scala has a very different solution to this problem, called | covariant and contravariant traits. | | I thought Scala had an even stricter value restriction than ML, | where only function/methods may get a polymorphic type? | eatonphil wrote: | For folks interested in learning Standard ML, check out /r/sml | [0] and the sticky post [1] with a getting started guide. | | [0] http://reddit.com/r/sml | | [1] | https://www.reddit.com/r/sml/comments/qyy2gs/getting_started... | jasonhansel wrote: | IMHO Haskell's lazy evaluation has some significant disadvantages | compared to SML's strict evaluation. In particular, lazy | evaluation makes it difficult to find the performance bottlenecks | in a particular piece of code or to determine the time complexity | of an algorithm just by reading it. | | Furthermore, subtle changes in how a function is written (for | instance, making a multiplication function not evaluate the right | operand if the left operand is zero) can cause wildly unexpected | performance changes in that function's callers. In effect, the | performance of a function is no longer just determined by that | function's structure and by the function calls it contains; | performance of one function now depends heavily on the | implementation details of others and the context in which that | function is used. | | Granted, any optimizing compiler can have this effect, but it's | rarely noticeable in strictly-evaluated languages, where at least | to some extent the order of evaluation must correspond to the | structure of the code. | porcoda wrote: | I still actively use SML - mlton or smlnj usually, polyml too. | I'm aware of the issues raised in this post but haven't ever | found them to be a source of much headache. To be honest, the | biggest headache is moving between compilers and their different | build processes. Other than that, the fact that the language | isn't really changing is a big attraction for me. | | CakeML is also a very cool project in SML land. | shpongled wrote: | SML is one of my favorite languages (I've been (very) slowly | writing a compiler & language server for it). | | Sure, it has some warts/differences compared to newer languages - | we have moved towards traits/typeclasses/etc, and I wish I could | just write #[derive(Debug) - but I feel that SML fits in a very | unique spot for programming languages. It's extremely simple, yet | still powerful and expressive. I hope we will see continued work | on SML/Successor ML descendants (like 1ML, etc), because I think | there's still potential there | | I think some updated language tooling would dramatically help. | jaytaylor wrote: | Is your development progress taking place in the open? (e.g. | GitHub or somewhere similar) | | It sounds like a cool project and I'd love to see it! And even | have the option to open a PR and help ;) | eatonphil wrote: | Yes, please share or open-source it even if it's not done! | shpongled wrote: | You have already linked to it :) | shpongled wrote: | I have the compiler on GitHub [1] - I just started working on | it again after a 2-year hiatus (to finish my PhD). | | As for language-server, I'm currently sketching out some | plans to use SMLnj's "Visible Compiler" feature, since that | seems the easiest path forward. I have a half-baked language- | server based on MLton's def-use output, but it's too unstable | to share. I am planning to make some progress on the | language-server in the next couple weeks. | | [1] You'll notice it's just a fragment of the language for | now, and only half-implemented. | https://github.com/SomewhatML/sml-compiler and | https://github.com/SomewhatML/sml-analyzer (again for a | fragment of SML) | bobbylarrybobby wrote: | > In Structure and Interpretation of Computer Programs, Abelson | and Sussman describe an arithmetic system in which the arithmetic | types form an explicit lattice. Every type comes with a | "promotion" function to promote it to a type higher up in the | lattice. When values of different types are added, each value is | promoted, perhaps repeatedly, until the two values are the same | type, which is the lattice join of the two original types. I've | never used anything like this and don't know how well it works in | practice, but it seems like a plausible approach, one which works | the way we usually think about numbers, and understands that it | can add a float to a Gaussian integer by construing both of them | as complex numbers. | | Julia uses this in pretty much all of its math functions and | probably elsewhere as well, and it works unbelievably well. The | type promotion system makes math Just Work, even (and especially) | in the face of different-sized numbers. The result is that 99.9% | of the time you simply don't have to think about the types of | your numbers. Here are some examples from the docs: | julia> promote_type(Int64, Float64) Float64 | julia> promote_type(Int32, Int64) Int64 julia> | promote_type(Float32, BigInt) BigFloat julia> | promote_type(Int16, Float16) Float16 julia> | promote_type(Int64, Float16) Float16 julia> | promote_type(Int8, UInt16) UInt16 | | And not only are types promoted, but in well-typed Julia code, | the deduction of promotion types happens at compile time instead | of runtime, so there is almost no performance cost to this | either. ___________________________________________________________________ (page generated 2022-04-30 23:00 UTC)