5 ms·
Monads are not about sequencing. They don't force applying functions in an order, at least any more than regular function application does. Haskell does not nee
by edflsafoiewq 4y ago
Monads are not about sequencing. They don't force applying functions in an order, at least any more than regular function application does. Haskell does not need them, they're just an interface and don't add anything to a language you can't do without them. The order of print statements is encoded the same way the order of elements in a list is, it's part of the definition of the data type. The monad instance says IO (IO a) is "the same as" an IO a, so really any sequencing ability implied in IO (IO a) already pre-exists in IO a.
- nightski 4y agoIt can catch newcomers off guard. People think they write - do a x b x in Haskell and that means the same as a sequential program (a runs before b). But this is not necessarily the case. It does not imply an order. It will only do so if the statements are dependent on each other - do c <- a x b c
- pxeger1 4y agoYou're technically right: a doesn't necessarily run before b, but that's pretty irrelevant. The only case in which it matters which one runs first are if one of the two results in an exception, which is rare especially in idiomatic Haskell code. The effect described by (a x) certainly runs before the effect described by (b x).
- deleted 4y ago[deleted]
- nightski 4y agoDoes it though? If I have the following - do f <- openFile "test.txt" putStrLn "Hello World" contents <- hGetContents handle In this case the file is most likely not opened before Hello World is printed to the console. However it would be opened before contents is read. This is what I mean in that the ordering is not top-down. It is dependency driven. This really tripped me up at first.
- pxeger1 4y agoI am unable to reproduce your claim. My exact code is: import System.IO main = do file <- openFile "hello.txt" ReadMode putStrLn "opened hello.txt" contents <- hGetContents file print contents I ran it with: ghc main.hs strace -fo strace.log ./main The strace log confirms the file is opened before putStrLn writes its output: ... 96748 openat(AT_FDCWD, "hello.txt", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 3 ... 96748 write(1, "opened hello.txt\n", 17) = 17 96748 read(3, "this is a file\n", 8192) = 15 96748 read(3, "", 8192) = 0 96748 close(3) = 0 ... 96748 write(1, "\"this is a file\\n\"\n", 19) = 19 ... Do you have an example that demonstrates IO not happening in the order of the monad? I really don't think what you say can possibly be right, but I'd like to see it if it is.
- nightski 4y agohttps://wiki.haskell.org/Do_notation_considered_harmful https://wiki.haskell.org/Do_notation_considered_harmful This article discusses it further, down around where it says "Newcomers might think that the order of statements determines the order of execution." and then proceeds to give examples further down. I have experienced this in the wild. I was working with a lot of data/csv parsing code along with some heavy computer vision work in haskell (3d reconstruction from point clouds using OpenGL and Repa, and custom algos) about a decade ago. It's been a while but I remember this happening quite well.
- edflsafoiewq 4y agoThat's not what they mean there. You're confusing the evaluation of an expression to its value, with the execution of that value when the value is an IO a. In x >> y, you can evaluate x and y in whatever order, but the program x >> y denotes always runs the program x denotes before the program y denotes. Similar to how in [x,y], x always comes before y in the list order, even if you evaluate y first.
- pxeger1 4y agoEvaluation order is somewhat "dependency driven" in Haskell for pure functions, because it uses lazy evaluation. But in this case the code here is basically generating a list of "instructions" for the Haskell runtime, like saying "first open the file, then say hello, then read the file". The generation of the instructions may be in an undefined order, but that doesn't matter, because writing the instructions doesn't in itself produce any side effects. The resulting list of instructions ends up listed in the order you wrote, and so the actual IO effects are executed in that order.
- shirogane86x 4y agoYeah I was about to write this. Thinking that monads are only about sequencing works only for IO, effectively. Option and Either are about short circuiting, and there's others that mess in execution state in hilarious ways (like the TARDIS monad and its time travelling shenanigans). I tried "understanding" monads for years but now I'm not really sure if there is anything to understand in particular. It's super simple and super generalized at the same time, it's really hard to explain why it is that way without going deep into scary mathy territory (while also preserving analogies that actually apply)
- afiori 4y agoSequencing here does not mean "building sequences" or "a monad is a sequence", but that the bind/>>= operator build monad values as a sequence of operations. For example with Lists the sequence is not the list itself but the sequence of flatMap[0]/bind/>>= operations necessary to build the desired list starting from `[a]` [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- jmillikin 4y ago> Monads are not about sequencing. They don't force applying functions > in an order, at least any more than regular function application does. Monads are about sequencing. This is easier to visualize if you de-sugar them: f = do x1 <- m 1 x2 <- m 2 return (x1 + x2) is an imperative form of f = m 1 >>= (\x1 -> m 2 >>= (\x2 -> return (x1 + x2))) You can see that there is no way to evaluate `x1` without first evaluating `m 1`, even if the result is a thunk. > Haskell does not need them, they're just an interface and don't > add anything to a language you can't do without them. How would you recommend implementing do-notation without the Monad typeclass? Applicative functors aren't enough. > The monad instance says IO (IO a) is "the same as" an IO a, so really > any sequencing ability implied in IO (IO a) already pre-exists in IO a. I don't see your point. That may be true of IO, but it's not true in general. `Maybe ()` and `Maybe (Maybe ())` are different types.
- simiones 4y ago> You can see that there is no way to evaluate `x1` without first evaluating `m 1`, even if the result is a thunk. Isn't this true of `f(g(x))` as well? You can't evaluate f(g(x)) without evaluating g(x) first, right?
- jmillikin 4y agoYep[0], and if you really wanted to, you could use that syntax to express the monadic interface: putStrLn :: TheWorld -> String -> (TheWorld, ()) main :: TheWorld -> (TheWorld, ()) main world = (part3, ()) where (part1, _) = putStrLn world "Hello" (part2, _) = putStrLn part1 ", " (part3, _) = putStrLn part2 "world!" It would be a frustrating user experience, but it's a valid and equivalent encoding to Haskell's `IO` type. [0] I'm ignoring lazy evaluation for now, but `f` could be implemented such that it returns before `g(x)` is evaluated. This is generally not relevant for purely functional code, but it can affect performance and exception-safety.
- afiori 4y agoLazy evaluation is exactly why Haskell has monads and Ocaml does not. the whole point of haskell was to see what happens if try to build a language with the strong requirement of lazy evaluation. If you remove it you also remove any need* for the IO monad * you can obviously use an IO like interface in a non-lazy language, but it is not necessary
- metanonsense 4y agoYou know that sentence "A monad is a monoid in the category of endofunctors, what’s the problem"? Being a "monoid" is exacly why monads are very much about sequencing.
- deleted 4y ago[deleted]