In what sense is IO monad special (if at all)?

After diving into monads I understand that they are a general concept to allow chaining computations inside some context (failing, non-determinism, state, etc) and there is no magic behind them.

Still IO monad feels even if not magic, but special.

  • you cannot escape IO monad like you can with other monads
  • IO action can only be run by the main function
  • IO is always at the bottom of a monad transformers chain
  • implementation of IO monad is unclear and source code shows some Haskell internals
  • What are the reasons for the points above? What makes IO so special?

    Update : in pure code evaluation order doesn't matter. But it does matter when doing IO (we want to save customer before we read it). From what I understand IO monad gives us such ordering guarantees. Is it a property of a monad in general or it is something specific to IO monad?


    you cannot escape IO monad like you can with other monads

    I'm not sure what you mean by “escape”. If you mean, somehow unwrap the internal representation of the monadic values (eg list -> sequence of cons-cells) – that is an implementation detail. In fact, you can define an IO emulation in pure Haskell – basically just a State over a lot of globally-available data. That would have all the semantics of IO , but without actually interacting with the real world, only a simulation thereof.

    If you mean, you can “extract values” from within the monad – nope, that's not in general possible, even for most pure-haskell monads. For instance, you can't extract a value from Maybe a (could be Nothing ) or Reader ba (what if b is uninhabited?)

    IO action can only be run by the main function

    Well, in a sense, everything can only be run by the main function. Code that's not in some way invoked from main will only sit there, you could replace it with undefined without changing anything.

    IO is always at the bottom of a monad transformers chain

    True, but that's also the case for eg ST .

    Implementation of IO monad is unclear and source code shows some Haskell internals

    Again: implementation is just, well, an implementation detail. The complexity of IO implementations actually has a lot to do with it being highly optimised; the same is also true for specialised pure monads (eg attoparsec).

    As I already said), much simpler implementations are possible, they just wouldn't be as useful as the full-fledged optimised real-world IO type.

    Fortunately, implementation needn't really bother you; the inside of IO may be unclear but the outside, the actual monadic interface, is pretty simple.

    in pure code evaluation order doesn't matter

    First of all – evaluation order can matter in pure code!

    Prelude> take 10 $ foldr (h t -> h `seq` (h:t)) [] [0..]
    [0,1,2,3,4,5,6,7,8,9]
    Prelude> take 10 $ foldr (h t -> t `seq` (h:t)) [] [0..]
    ^CInterrupted.
    

    But indeed you can never get a wrong, non-⊥ result due to misordered pure-code evaluation. That actually doesn't apply to reordering monadic actions ( IO or otherwise) though, because changing the sequence order changes the actual structure of the resultant action, not just the evaluation order that the runtime will use to construct this structure.

    For example (list monad):

    Prelude> [1,2,3] >>= e -> [10,20,30] >>= z -> [e+z]
    [11,21,31,12,22,32,13,23,33]
    Prelude> [10,20,30] >>= z -> [1,2,3] >>= e -> [e+z]
    [11,12,13,21,22,23,31,32,33]
    

    All that said, certainly IO is quite special, indeed I think some people hesitate to call it a monad (it's a bit unclear what it's actually supposed to mean for IO to fulfill the monad laws). In particular, lazy IO is one massive troublemaker (and best just avoided, at all times).


    Similar statements could be made about the ST monad, or arguably the STM monad (although you can actually implement that one on top of IO ).

    Basically things like the Reader monad, Error monad, Writer monad, etc., are all just pure code. The ST and IO monads are the only ones that really do impure things (state mutation, etc), so they aren't definable in pure Haskell. They have to be "hard-wired" into the compiler somewhere.

    链接地址: http://www.djcxy.com/p/80876.html

    上一篇: 功能性程序设计:副作用实际发生在哪里?

    下一篇: IO monad是什么意思(如果有的话)?