3 ms·
>At the end of the day, this is a huge inner-framework anti-pattern over the same procedural syscalls that every other language handles procedurally. No, you h
by imanaccount247 12y ago
>At the end of the day, this is a huge inner-framework anti-pattern over the same procedural syscalls that every other language handles procedurally.
No, you have a tiny, very simple type that allows for type safe IO. It also happens to make haskell a more powerful imperative language than most imperative languages, as IO actions are first class and can be passed around and manipulated like anything else.
>So, basically, they acknowledge that their theoretical model has a huge impedance mismatch with what we write programs to do (I/O, eventually, somewhere)
No, they acknowledge that doing IO is so important that it should be done correctly. You are going to some pretty extreme mental gymnastics to misrepresent a language you want to hate.
- yarou 12y agoTo be fair, understanding I/O in Haskell takes quite a bit of mental gymnastics. :) The I/O monad modifies the Universe that contains the set of all functions that comprise your program (if I even understand the concept correctly).
- tome 12y ago> The I/O monad modifies the Universe that contains the set of all functions that comprise your program That sounds rather complicated. My way of thinking of it is simpler than that. a -> IO b is just a function from a to b that can do some I/O. Nothing more complicated than that.
- wbillingsley 12y agoIt is (slightly) more complicated than that. Your return type is not b but IO b. Your callers will be performing functions that are defined on IO b with the result (such as bind)
- SamReidHughes 12y agoI recommend just regarding IO a as an action, or some description of an action, that returns a value of type a. And (>>=) constructs bigger actions by attaching continuations to actions.
- spion 12y agoThe IO monad is just an action. Its a cons pair with a left and a right half. In an imperative language you could model the left half with a closure that takes no arguments, does I/O and produces a value. The right half is usually empty, except when you use the `>>=` operator (or flatMap) on an existing action, e.g. let c = a >>= f That operator chains the function `f` can take the value produced by the first IO action and produce another IO action. After we apply that operator, the result `c` is a cons cell where the left part is the original action `a` and the right part is the function f which takes the value produced by a and produces the next action. Its sort of like a cons cell in regular lists, except the next value is provided by a function. A lazy cons cell, perhaps :) The final result is a lazy chain of I/O cons cells (called "main", of course :P). Its passed to the Haskell runtime, which executes that chain as a recipe, alternating between doing I/O actions and evaluating the function to decide what to do next. So what does this buy us? Mostly just referential transparency. What does referential transparency buy us? Easy refactoring. We can replace any expression with its value, even stuff like `putStrLn "test"`. We can say `let writeTest = putStrLn "test"` at the top of the file then write `do writeTest; writeTest` in main. Another neat thing is that do syntax isn't limited to just IO, but works with anything that implements `flatMap` (and `unit`, which I forgot to mention). That means we can build our own imperative DSLs that produce IO-like monads which are then interpreted by our own interpreter, and the users of those DSLs can use the same do syntax. Which is pretty awesome. Here is a simple example: https://gist.github.com/tonymorris/b5dba9d7d877051d0164 https://gist.github.com/tonymorris/b5dba9d7d877051d0164 and a much more complex one http://augustss.blogspot.com/2009/02/more-basic-not-that-anybody-should-care.html http://augustss.blogspot.com/2009/02/more-basic-not-that-any... :)