4 ms·
The difference is given by the code context (which is unfortunately entirely missing from the article). What’s shown here are the things all these patterns have
by klmr 9y ago
The difference is given by the code context (which is unfortunately entirely missing from the article). What’s shown here are the things all these patterns have in common. The whole point of abstraction is to have different, but related, things look the same.
Haskell (and these examples) certainly raise the level of abstraction to extremes (compared to other languages). But as long as the context (explicit type annotations, if necessary) make it clear what the code does, I don’t see this (even conceivably) as a disadvantage.
- xenomachina 9y ago> But as long as the context (explicit type annotations, if necessary) make it clear what the code does, I don’t see this (even conceivably) as a disadvantage. I spent 3 years trying to learn Haskell, and I never found this clear. When you see a "do" block, where do you look to figure out what it's actually doing?
- dllthomas 9y ago> When you see a "do" block, where do you look to figure out what it's actually doing? If you need to know, you look at what consumes the result. If it's abstract (say it's a top level binding `... -> m a` where the m is abstract) you don't need to know "what it is actually doing" - it should be correct for any choice of `m`. Whether this stuff is easy to find/follow certainly depends on the quality of the code, as well as your experience. It's not something I struggle with, working day-to-day in Haskell.
- dmitriid 9y ago> you don't need to know "what it is actually doing" - it should be correct for any choice of `m`. I don’t know what it’s doing, but it’s correct. :-/ So what is it doing that’s correct? Or is it some abstract correctness?
- dllthomas 9y agoIt's not abstract correctness, it's satisfying contracts up to an interface. Take `sequence :: Monad m => [m a] -> m [a]` That takes a list of actions and gives us an action that runs each in turn and collects the results in order. The correctness relative to that description is clear regardless of whether each input action is threading state or handling failure or printing to the screen.
- dmitriid 9y agoThen this clearly doesn’t answer the original question, does it?
- deleted 9y ago[deleted]
- dllthomas 9y agoNot on its own. Fortunately, it wasn't the entirety of my answer to the original question. When you're writing something like `sequence`, you don't need to know the implementation of the interface you're working against. As you get comfortable in Haskell, more things are "like `sequence`". There will always be things that aren't - for those, as I said, you should look where the value is consumed. And as I neglected to say, you can always add a type annotation when things get unclear.
- dmitriid 9y agoAh, the old Java adage: any abstraction can be solved with many more layers of abstraction.
- Izkata 9y ago> If you need to know, you look at what consumes the result. If it's abstract (say it's a top level binding `... -> m a` where the m is abstract) you don't need to know "what it is actually doing" - it should be correct for any choice of `m`. That seems to explain a lot. So to make an ad-hoc version of the Elvis Operators section that's actually equivalent to the Haskell code would be more like this? ___ a ___ getData(); ___ b ___ a ___ getMoreData(); ___ c ___ b ___ getMoreData(); ___ d ___ c ___ getEvenMoreData(a); print(d);
- leshow 9y agoLook at the return type of the function and you can tell what instance it's using, if it's using something that's a type variable, then it's instance isn't important, just it's interface.
- tikhonj 9y agoI work on largeish commercial Haskell codebase and I never have to look anywhere to figure it out—I know what the do block is doing because I know what function it's in and what the return type is. With a bit of experience I started keeping track of this context subconsciously so the question just doesn't come up. Haskell code tends to rely on context quite a bit. This does make it more difficult to learn, but once you're over the hump, context is something you end up understanding automatically.
- xenomachina 9y agoWhat makes this confusing for me is that this is backwards from the way expressions work pretty much anywhere else. It should be possible to know the type of a sub-expression without knowing anything about the expression that contains it. That is, start at the leaves, and work your way up. In Haskell, sometimes you have to go the other way. It's like trying to read a novel where some chapters randomly assume you know what happens several chapters later.