4 ms·
The point is not that any one example is better than the other, rather it's that the same syntax can be used to uniformly solve multiple different problems (par
by alipang 9y ago
The point is not that any one example is better than the other, rather it's that the same syntax can be used to uniformly solve multiple different problems (partiality, async, "non-determinism", and state-passing).
- xenomachina 9y agoOne thing this article doesn't really make clear is how someone reading the code can actually determine which of these things is being done. Code that looks the same but magically does something different doesn't seem like an improvement to anyone who wants to be able to maintain their code. I know enough Haskell to know that the "magic" comes from which instance of Monad is being used, but between the weirdness of overloaded values, the fact that the "do" syntax doesn't really make it obvious which value is the important one, and Haskell programmers' aversion to using parens, I still find this stuff impossibly hard to read. This is largely why I gave up on Haskell after trying to learn it for 3 years.
- thinkpad20 9y agoThere are two answers I can think of: 1. You know what the code is doing to the extent that you know how monads work. As in, you know that you’re going to do some monadic action that returns a, then another one that returns b, etc. The code as written is generic so it’s not specified what the actions are. 2. And this is the much more common case; the code in question is being used within a particular context (I.e. for a particular monad that the programmer is working with) and the context makes it obvious what is actually being done by the monadic actions. Here the genericness is not in writing a function that can be used in multiple places, but in having a portable concept of “a pipeline of actions that return things and could fail” which you can use wherever you need it.
- platz 9y agoWhat resources did you use
- xenomachina 9y agoWhat kind of resource do you mean? It's been a few years now. I know I read LYAH, and I think also one of the O'reilly books. I used GHC and vim+syntastic. I used Hoogle for looking stuff up. I asked lots of questions on Stack Overflow, Reddit, and one of the IRC channels. Even after 3 years, everything with Haskell felt like rolling a boulder up a hill. The only reason I'd persisted as long as I did was because the idea of a purely functional statically typed language really appeals to me. Despite those features being what I've wanted in a language for decades, too much about Haskell makes it unusable for me. I did learn some useful stuff in the process, but came away with the conclusion that virtually all of the good stuff in Haskell does not really need to be coupled to all of the terrible stuff in Haskell. I think for some people (I suspect a tiny minority) of the people who attempt to learn Haskell, they get past the terrible stuff and either stop seeing it, or become brainwashed into thinking it's unavoidable/necessary. Perhaps it only works for the 5% of people who's brain happens to be wired the right way, I don't know. Most people, though, give up. To make matters worse, if you are not one of those people for whom the weirdness of Haskell "clicks", and you mention that parts of it make no sense to you, you'll get very little help from the Haskell community. Most will tell you things like "I use Haskell every day, and this doesn't bother me". Great. That said, during the time I was trying to learn Haskell I did see some small improvements being made in the usability department. The biggest by far was that they finally turned off MR by default. Still, too little too late for me, so I ended up giving up on Haskell and moving on to other languages where I can actually understand my own code a day or two later. As an aside, MR was a great example what's wrong with Haskell: 99% of the time the language designers don't seem to care about usability at all, but the 1% of the time they actually try to do something to help usability, their attempts completely backfire. map vs fmap is another example of this, though not nearly as horrendous as MR.
- haskellandchill 9y agoType at point in an IDE helps. You can also use type holes and let the compiler infer types that you can use as a guide to fill in.
- xenomachina 9y agoYeah, I feel like a powerful enough IDE could probably make Haskell usable. Something that made the types obvious, and also the nesting of subexpressions. Despite trying for 3 years, I never felt like I could even reliably parse Haskell code in my head (too many fixity rules, not enough parens) let alone infer the types of things.
- marcosdumay 9y agoWell, the `do` syntax makes it patently obvious what is the important value, it is the one being assigned into variables within the block and used as argument of functions. It hides the not so useful one that is the name of the monad you are using. You know the kind of "magic" by looking at the type declaration on the line just above that `do`. If there's no type declaration there, I hope the code is simple enough that it is self explanatory, otherwise it's plain bad code. Things are made more complex when the monad type is generic. But then, this just makes it patently visible that the monad does not matter at all and the code must work as intended on any kind of "magic" you can throw at it. About the aversion to using parens, matched operators make your code brittle and hard to change. This is not obvious if you have never seen any other way of organizing code, but it is a large effect.
- xenomachina 9y ago> the `do` syntax makes it patently obvious what is the important value Given that it seems that the majority of people who attempt to learn Haskell end up giving up, I'd argue that very little about it is "patently obvious". > it is the one being assigned into variables within the block and used as argument of functions I think this is part of what confounds me when it comes to Haskell (aside from the terrible syntax and horrible coding conventions): when I'm reading an expression I understand the overall expression by understanding what the sub-expressions do. That is, I can start at the leaves of the expression tree and work my way up to the root. In Haskell, sometimes this is not possible, because sometimes the type of the subexpression is constrained by something higher up in the AST. This leaves me not knowing where to start with trying to decipher the type of an expression. > About the aversion to using parens, matched operators make your code brittle and hard to change. This is not obvious if you have never seen any other way of organizing code, but it is a large effect. What are "matched operators"? The aversion to using parens means that I can't even parse code unless I know the fixity rules of all of the operators in an expression. I'm sure you'll say this is easy to pick up after a while, but that has not been my experience.
- marcosdumay 9y ago> In Haskell, sometimes this is not possible, because sometimes the type of the subexpression is constrained by something higher up in the AST. The point is that this constraint always have the exact same format. It may have some different semantics, but Haskell makes you abstract over those to get into the operational function, while the compiler verifies anything that isn't local operations to fit your overall structure. Really, learning Haskell is the process of learning to abstract semantics away from your code. It's a hard process, it's not something natural. > What are "matched operators"? Those are operators that require a matching. Usually parenthesis, square brackets and braces. Haskell has the unmatched operators `.` and `$` that people use instead, and for reading it you do have to understand their priority. Most operators do not a set fixity, but those two are a must.