6 ms·
> This begins to get us to the fundamental abstraction of a monad: a box, with an interface for map, and flatMap Before I understood monads, I read variations
by ridiculous_fish 6y ago
> This begins to get us to the fundamental abstraction of a monad: a box, with an interface for map, and flatMap
Before I understood monads, I read variations of the above sentence a million times, always got stuck here: https://i.imgur.com/McThkuh.png https://i.imgur.com/McThkuh.png
How does this abstraction let us perform IO, do in-place destructive updates, etc? The answer is that it doesn't. These must be primitives supplied by the runtime. A monad like IO has its two functions (return+bind), and a bunch of other magic functions. It's obvious now but that fact is hardly ever stated.
I wonder if anyone has tried explaining from the other direction? Rather than building up to Maybe, try building down from a desire to print Hello World.
- chowells 6y agoI think most of this happens because lots of people say things like "the IO monad" when they actually just mean "IO". It misleads people into thinking the monad part is important. It isn't. IO is the tough concept. Monad is almost trivial.
- ridiculous_fish 6y agoGood point, I agree. But you must learn it to get anything done. Grappling with IO + monad + do-notation all at once is hard! I once spent a day thinking I had misunderstood something fundamental, but really I just had an errant tab instead of a space.
- dllthomas 6y ago+ type inference + return-type polymorphism!
- chowells 6y agoOk, yes. Monads as a concept are almost trivial in comparison to thinking in terms of the IO type. But that doesn't mean they are easy and don't add more hurdles to get over. I think I undersold how daunting it can be to face all the new things at once, and you're right about it.
- yomly 6y agoAs a recent Haskell learner, I found the indentation part of Haskell hard to learn and a little undiscoverable/hard to google. The number of times I've used curly braces, single lines or expression substitution to bail me out is many...
- neckardt 6y agoYou might like hinc, it's haskell but with C style syntax: https://github.com/serras/hinc/blob/master/why.md https://github.com/serras/hinc/blob/master/why.md
- scns 6y agoI like it. "This is not by coincidence: people learning Haskell usually have problems with point-free style not because of the composition operator per se, but because code is suddenly "reversed". Other communities such as F# have adopted the "pipe forward" operator instead of composition as the default style." That's why i prefer the reverse application operator & to .
- yomly 6y agoThanks for the suggestion but Haskell would not be Haskell without its ML-yness. As confusing as operator precedence can get, I do see the beauty in "programmable whitespace" but to get anywhere close in other language syntaxes you need to do even more perverse things like here [1] If I did have to choose a different syntax for haskell it would be S-expressions rather than Algol so perhaps Hackett from Lexi Lambda [1] https://stackoverflow.com/a/48553568 https://stackoverflow.com/a/48553568
- raiflip 6y agoA monad really is just a wrapper around a value, with flatMap and return. For some kinds of monads, like maybe, that’s all you need. But, some other kinds of monads need more logic. List is one, IO is another. In OOP language, sometimes all you need is the parent class. But sometimes you need to extend the parent and add more.
- ratww 6y agoIt's actually more like an abstract class! Even the Maybe monad has some implementation, it's just super simple :) https://hackage.haskell.org/package/base-4.14.0.0/docs/src/GHC.Base.html#line-1005 https://hackage.haskell.org/package/base-4.14.0.0/docs/src/G...
- raiflip 6y agoTotally agree, that’s a good point.
- anchpop 6y agoWhat you say is correct, but let me try and explain a little further. The Haskell function `getChar` is used to get a character from stdin. It has the type `IO Char` and is a totally, 100% pure. In fact, it isn't even a function, it's just a value. You can write `getChar` as many times as you want, and you will get the same result every time, and it will have nothing to do with whatever character is being sent to stdin. Instead, what you will get is an instruction, saying "please get a character from stdin". What the IO monad allows you to do is to compose instructions together. For example, you could write `getChar >> getChar". This makes a new instruction that says "please get a character from stdin, discard it, then get a character from stdin". The `>>` operator means "follow the instruction on the left, discard the result, then do the instruction on the right". Your entire program is made by composing instructions like this, into one new huge instruction that specifies your entire program's behaviour. You assign that to the special name `main`. At runtime, the instruction is executed. The only bit of compiler magic that's necessary is the code for interpreting the instructions and actually executing them. In theory, although haskell doesn't let you do this, you could write `getChar` yourself, and just return the same thing that `getChar` does, and it would behave identically. This I feel is the simplest explanation for why monads are necessary in Haskell. They allow you to conveniently specify what you want your program to do, using only pure functions and values. Why do you want all values to be pure? Many don't because it's kind of a pain, but Haskell kind of exists to see if a lazy, pure functional language can be fun to use and many find that it is. Hope this helps someone!
- choeger 6y ago> In fact, it isn't even a function, it's just a value. What's the difference?
- dllthomas 6y agoFunctions are values, but values that are not functions are those that cannot be supplied an argument.
- ridiculous_fish 6y agoGreat description of IO, but I think it doesn't actually motivate monads. Your example of `getChar >> getChar` could be simply `[getChar, getChar]`. Why can't we just compose instructions into an ordinary list? The answer is that we can, and Haskell used to work this way [1]! So as 'chowells' observed the monad-part of IO is almost incidental. 1: https://stackoverflow.com/questions/17002119/haskell-pre-monadic-i-o https://stackoverflow.com/questions/17002119/haskell-pre-mon...
- agumonkey 6y agoto me the issue is twofold: - cultural reliance on lambdas as the universal force (nothing against lambdas, but outside the fp world, there will be too much culture shock) - representation as computation, the monad is only kinda building a graph to be evaluated, and each node can be wrapped with rules as you see fit
- AnimalMuppet 6y agoHmm. Your last line makes me think that they're, essentially, using monads to represent S-expressions. That seems... somewhat clumsier than just using S-expressions. You gain a really good type system, though.
- agumonkey 6y agoI'm so not an expert I hope people don't read me too seriously. It's just my understanding of the FP world. A lot of time they will encode ideas in threaded closures that do nothing until they're consumed (the programmable semicolon doing the 'interpretative' part) which is a bit like a DSL tree and not so removed from a ~lisp.
- 08-15 6y ago> the monad is only kinda building a graph to be evaluated That's what the free monad does. Not every monad is a free monad, IO certainly isn't.
- edflsafoiewq 6y agoWhy isn't IO free?
- 08-15 6y agoCome think about it, it could be. That's not how it's implemented in any Haskell implementation I know of.
- scns 6y ago
- goto11 6y agoYeah this is like saying objects lets us perform IO in Java, and then going deep into explanations of what objects are and what rules they obey (Liskov substitution principle etc) - instead of just explaining that you call println() to write "hello world".
- yomly 6y agoWe often forget how much assumed knowledge (and accepted knowledge) went into learning OOP. Turing Machine and Lambda Calculus are two entry points into computational thinking, is it really so alarming that if you've only learned one that trying to learn the other will make you feel like a beginner all over again?
- Izkata 6y agoY'know what, maybe looking at it like that is actually one of the problems: We don't learn our first imperative language(s) by way of Turing machines. That theory-level understanding comes much later, after we have a handle on the language itself. When first learning, the most common abstractions are variations on "a list of steps" - like an instruction manual or To-do list - without touching on memory. I wonder if there's some sort of similar abstraction here that could be used instead, for the just-getting-started stage...
- yomly 6y agoExcel function pipelines which take inputs to outputs. People build wonderfully useful things in Excel using its standard library of spreadsheet functions. They are all referentially transparent. In imperative steps of code, time flows down your code. In functional code your flow of time is each function application.
- goto11 6y agoThis is what I call haskellsplaining - explaining concept from first principles and mathematical definitions rather than from how they are used and what they are useful for.
- smitty1e 6y agoI think the sticky wicket with Haskell is less the terse syntax and more the execution model. Why not start enumerating the lines of a file, and show how we're building up a list of thinks, and there is no actual variable representing the line numbers because state is for Statists?