5 ms·
Don't get me wrong, I like Elm a lot, but the drop in expressiveness/ability to build abstractions from Haskell is substantial. Especially when you're looking a
by zenhack 7y ago
Don't get me wrong, I like Elm a lot, but the drop in expressiveness/ability to build abstractions from Haskell is substantial. Especially when you're looking at modularity, there are a bunch of things that Elm can't abstract out that both Rust and Haskell can manage just fine.
I haven't used Rust heavily enough to comment on how it compares in great detail, but comparing to Elm as a proxy for Haskell doesn't really work.
Frankly, paradigms are a really lousy way to think about languages. I wrote a series of blog posts about this[1], but this opening lecture from one of Brown's PL courses I think does a better job of making the point:
https://www.youtube.com/watch?v=3N__tvmZrzc https://www.youtube.com/watch?v=3N__tvmZrzc
It's useful to talk about what say, GC, laziness, lifetimes, ownership, typeclasses/traits, higher-kinded types, higher rank types, variants, elm-style records, etc. do to a language, and how they compose, but I think you can't go very far talking about how "paradigms" compare.
[1]: https://zenhack.net/2018/07/14/three-funerals-in-the-name-of-clarity-3-systems.html https://zenhack.net/2018/07/14/three-funerals-in-the-name-of...
- rtfeldman 7y ago> It's useful to talk about what say, GC, laziness, lifetimes, ownership, typeclasses/traits, higher-kinded types, higher rank types, variants, elm-style records, etc. do to a language, and how they compose, but I think you can't go very far talking about how "paradigms" compare. Sure. My experience has been: * GC, lifetimes, and ownership are all high-benefit and high-cost. The cost with GC is at runtime (where the cost is so high that in many domains GC is not tolerated at all; in many others, of course, we take it for granted as fine), and the high costs of lifetimes and ownership are at development time. * Variants and records are high-benefit, low-cost. * Higher-rank types are low-cost, low-benefit. * Laziness and higher-kinded types are both features with costs that significantly outweigh their benefits. It sounds like you disagree with the last bullet point. If so, then either we've had different experiences or we walked away with different conclusions from them.
- zenhack 7y ago> * Laziness and higher-kinded types are both features with costs that significantly outweigh their benefits. > It sounds like you disagree with the last bullet point. If so, then either we've had different experiences or we walked away with different conclusions from them. I more or less agree on laziness (at least lazy-by-default; having a lazy type as found in OCaml available is a big win for little downside). Re: Higher-kinded types: I'm curious as to what you think the high costs are? My impression is that they've mostly been left out of Elm due to pedagogical concerns. Is it just that or are there other things?
- rtfeldman 7y agoLearning curve is a very high cost by itself; HKP is the reason Haskell is notoriously difficult to learn. (Compare to Elm, which is also a referentially transparent typed ML with parameteric polymorohism and row types, with nearly identical syntax to Haskell...and which is notoriously easy to learn.) Haskell beginners don't need to get into GADTs and type families and higher-ranked types, but HKP is practically unavoidable on the road to understanding a Haskell program that prints Hello World. Another cost is in standard library complexity. You can't have HKP and not have a stdlib with Functor/Monoid/Monad etc. As Scala has demonstrated, if you have HKP but don't put these in the stdlib, a large faction will emerge pushing an alternative stdlib that has them. A larger, more complex stdlib is a cost, and so is a fractured community and ecosystem; HKP means you'll have to pick one of those two. API design is another. Without HKP you write a function that takes a List. With HKP you now need to decide: should it actually take a List, or is it better to take a Functor/Semigroup/Monoid/Applicative/Monad instead? If you choose one of the more generic ones, now it takes more mental steps to collapse the indirection when reading it. (1. I have a Maybe Int. 2. This function expects an `s`. 3. `s` is constrained by `Semigroup s`. 4. Can I pass a Maybe Int to something expecting a Semigroup? Compare to "This function takes a `Maybe a`", and multiply that small delta of effort by a massive coefficient; this is something everyone who reads these types will do many, many times.) This indirection also has implementation costs; in theory you could make docs and error messages about as nice if HKP is involved as if not, but there's an implementation cost there, and it seems like it must be pretty steep if you stack up languages with HKP and their quality of error messages and docs against other typed languages that don't. So I'd say it's one huge cost (automatic induction into the highest tier of learning curve steepness), one big cost (either a larger and more complex stdlib or fractured community), and several smaller costs with high coefficients because they come up extremely often. Yeah there are benefits too, but I don't think they get anywhere near outweighing the costs.