4 ms·
> Attacking Haskell is sort of a straw man--so far I haven't seen anyone in this thread propose Haskell as a go alternative. I think we agree Haskell is far too
by mrkeen 2y ago
> Attacking Haskell is sort of a straw man--so far I haven't seen anyone in this thread propose Haskell as a go alternative. I think we agree Haskell is far too dogmatic about its abstractions when it's impractical to be used as a general-purpose language (because I don't think it's intended as a general-purpose language).
I'll be that guy. We like our stuff in Haskell. Watching the rest of the industry move forward is like a reverse trip around the Monopoly board of computer science progress.
When I joined up, everything was Java, which couldn't make a binary. Then the crowd jumped to JS, where we ditched integers and true parallelism. Python freed us from speed. Go came along, promising to remove generics and exceptions, and to finally give us back our boilerplate.
And whenever features progress in the forward direction again, there are two issues - firstly, they sometimes come out kind of crap. Secondly, arguments for or against this crapness tend to take up all the oxygen that could have facilitated discussions around goodness.
Exceptions or return values? Nope, monadic error handling, any day of the week.
Terse dynamic code, or bloated static code? Nope, terse code with full type inference.
Terse nulls or nulls & boilerplate Optionals? Nope, just terse Optionals.
First-order generics or no? Higher-kinded parametric polymorphism.
Multiprogramming via locking & shared memory or message passing? Hey how about I choose between shared-memory transactions or transactional message-passing instead?
There is little stuff happening outside of Haskell to be envious of. Java took a swing at the null problem with Optionals a decade ago. My IDE warns me not to use them. It's taking another swing with "Null-Restricted Value Class Types". I know your eyes glaze over when people rant about Haskell, but for two seconds, just picture yourself happily doing your day-to-day coding without the existence of nulls, and pretend you read a blog post about exciting new methods for detecting them.
- the_gipsy 2y ago> everything was Java, which couldn't make a binary. Then the crowd jumped to JS, where we ditched integers and true parallelism. Python freed us from speed. Go came along, promising to remove generics and exceptions, and to finally give us back our boilerplate. That paragraph made me chuckle, thanks. > picture yourself happily doing your day-to-day coding without the existence of nulls I've seen it, with Elm and Rust, and now I hate go's "zero values" too because it makes everything a bit more like PHP aka failing forward.
- RandomThoughts3 2y agoThe issue is not language semantic. The issue is readability. Having the best feature set in the world is useless if the code produced by others is a pain to decipher. Haskell disqualified itself for general programming when its community decided that point-free was desirable despite the style being impossible to read and custom operators were a good thing. I personally hate every Haskell code base I have ever seen despite being relatively fluent in the language (an issue Ocaml never had amusingly mostly because its community used to be very pragmatic).
- tome 2y agoSo when you said > I think we agree Haskell is far too dogmatic about its abstractions when it's impractical to be used as a general-purpose language did you mean "sometimes some Haskellers use point-free style and it's impossible to read"? If not, could you explain what you did mean?
- kerkeslager 2y agoThe person you are responding to didn't say that, I did. The abstractions I'm pointing at are cases where mutation or side effects are the desired result of execution. Ultimately this always runs up against having to grok a lot of different monads and that's simply never going to be as easy to understand as calling "print" or "break". Haskell works really well if the problems you're solving don't have a ton of weird edge cases, but often reality doesn't work like that. The other thing is laziness which makes it hard to reason about performance. Note that I didn't say it's hard to reason about execution order--I think they did a good job of handling that. Don't get me wrong, Haskell's dogmatic commitment to functional purity has led to the discovery of some powerful abstractions that have trickled out into other languages. That's extremely valuable work.
- tome 2y ago> The person you are responding to didn't say that, I did. Ah, thanks, I got confused. > Haskell works really well if the problems you're solving don't have a ton of weird edge cases, but often reality doesn't work like that. In my experience it's completely the opposite, actually. I can only really write code that correctly handles a ton of weird edge cases in Haskell. It seems that many people think that Haskell is supposedly a language for "making easy code elegant". The benefit of Haskell is not elegance or style (although it can be elegant). The benefit is that it makes gnarly problems tractable! My experience trying to handle a ton of weird edge cases in Python is that it's really difficult, firstly because you can't model many edge cases properly at all because it doesn't have sum types and secondly because it doesn't have type checking. (As I understand it they have added both of these features since I last used Python, but I suspect they're not as ergonomic as in Haskell.) > this always runs up against having to grok a lot of different monads and that's simply never going to be as easy to understand as calling "print" or "break" Actually, I would say not really. The largest number of monads you "have to" learn is one, that is, the monad of the effect system you choose. Naturally, not every Haskell codebase uses an effect system, and those codebases can therefore be more complex in that regard, but that's not a problem with Haskell per se, it's an emergent property of how people use Haskell, and therefore doesn't say anything at all about whether Haskell is usable as a general purpose language. For example, consider the following Python code. def main(): for i in range(1, 101): if i > 4: break print(i) You can write it in Bluefin[1], my Haskell effect system as follows. main = runEff $ \ioe -> withJump $ \break -> do for_ [1..100] $ \i -> do when (i > 4) $ do jumpTo break effIO ioe (print i) Granted, that is noisier than the Python, despite being a direct translation. However, the noise is a roughly O(1) cost so in larger code samples it would be less noticeable. The benefit of Haskell here over Python is 1. You don't get weird semantics around mutating the loop variable, and it remaining in scope after loop exit 2. You can "break" through any number of nested loops, not just to the nearest enclosing loop (which is actually more useful when dealing with weird edge cases, not less) 3. You can see exactly what effects are possible in any part of the program (which again is actually more useful when dealing with weird edge cases, not less) Regarding laziness and performance, that is a resolved issue. I have an article that explains that: http://h2.jaguarpaw.co.uk/posts/make-invalid-laziness-unrepresentable/ http://h2.jaguarpaw.co.uk/posts/make-invalid-laziness-unrepr... I'm curious what you think of Haskell suitability for general purpose programming in light of my response. [1] https://hackage.haskell.org/package/bluefin-0.0.6.1/docs/Bluefin.html https://hackage.haskell.org/package/bluefin-0.0.6.1/docs/Blu...
- kerkeslager 2y ago> Exceptions or return values? Nope, monadic error handling, any day of the week. Ehhhh... The thing is, there are a lot of cases where I can look at the code and I know the error won't happen because I'm not calling it that way. Sure, sometimes I get it wrong, but the fact is that not every application needs a level of reliability that's worth the effort of having to reason around error handling semi-explicitly to persuade the compiler that the error is handled, when it really doesn't need to be. > Terse dynamic code, or bloated static code? Nope, terse code with full type inference. I think you're significantly overselling this. Type inference is great, but you can't pretend that you don't have to implicitly work around types sometimes, resulting in some structures that would be terser in a dynamic language. Type inference is extremely valuable and I really don't want to use static types without it, but there are some tradeoffs between dynamic types and static types with type inference that you're not acknowledging. I think for a lot of problems Haskell wins here, but a lot of problems it doesn't. One area I'm exploring with the interpreter I'm writing is strong, dynamic typing. The hypothesis is that the strictness of the types matters more than when they are checked (compile time or runtime). Python and Ruby I think both had this idea, but didn't take it far enough in my opinion, making compromises where they didn't need to. > Terse nulls or nulls & boilerplate Optionals? Nope, just terse Optionals. 100% with you on this. > First-order generics or no? Higher-kinded parametric polymorphism. Ehhh, I feel like this is getting overly excited about something that simply isn't all that useful. I'm sure that there's some problem out there where higher-kinded types matter, or maybe I just lack vision, but I'm just not coming across any problems in my career where this feels like the solution. I feel like there's a caveat I want to add to this but I'm not able to put my finger on it at the moment, so bear with me if I revise this statement a bit later. :) > Multiprogramming via locking & shared memory or message passing? Hey how about I choose between shared-memory transactions or transactional message-passing instead? Ehh, the languages I like are all using transactional message-passing anyway, and I'm pretty sure Haskell didn't invent this. > There is little stuff happening outside of Haskell to be envious of. Java took a swing at the null problem with Optionals a decade ago. My IDE warns me not to use them. It's taking another swing with "Null-Restricted Value Class Types". I know your eyes glaze over when people rant about Haskell, but for two seconds, just picture yourself happily doing your day-to-day coding without the existence of nulls, and pretend you read a blog post about exciting new methods for detecting them. I mean sure, I'm 100% with you on Option types, as I said. But, imagine being able to insert `print(a)` into your program to see what's in the `a` variable at a specific time. Hey, I know that's not pure, but it's still damn useful.