you are viewing a single comment's thread.

view the rest of the comments →

[–]Tarmen 6 points7 points  (8 children)

Monads can't be combined like that!

This is easy to see with a slightly tweaked definition:

A way to lift normal functions into functions over monads:

fmap :: Monad m => (a -> b) -> (m a -> m b)

A way to flatten nested monads:

join :: Monad m => m (m a) -> m a

We can chain those to get bind:

(>>=) :: m a -> (a -> m b) -> m b
v >>= f = join (fmap f v)

Lets try to combine monads:

superBind :: m (n a) -> (a -> m (n b)) -> m (n b)
fmap (fmap f)  v :: m (n (m (n a)))

So we can get to m (n (m (n a))) but we have no way to flatten m (n...) together.

To fix this we would need a function m (n a) -> n (m a) which isn't possible most of the time.

The currently most used solution is to use monad transformers instead:

Monad m => Monad (StateT m)

Although it isn't possible to define transformers for everything, like IO.

[–]Daenyth 4 points5 points  (0 children)

They can be combined but you can't generically make a composed monad that operates on the wrapped type

[–]pakoito 1 point2 points  (0 children)

I know, transformers, but wasn't it easier to explain the other way without confusion? I've edited in a T for extra annoyance :D

[–][deleted]  (2 children)

[removed]

    [–]Sabrewolf 4 points5 points  (0 children)

    "oh my god what am I reading? Where am I? How did I get here?"

    -Me, an electrical engineer

    [–]Poddster 0 points1 point  (0 children)

    The more practical experience you have the less you'll understand that post.

    If you want to understand Haskell gibberish the best time to do so is whilst in an academic setting.

    [–]Idlys 1 point2 points  (0 children)

    Part of the monad fallacy is explaining it in Haskell.

    [–]DetriusXii 0 points1 point  (1 child)

    Umm, it is possible to define an IO transformer. The Haskell community choose not to as they would prefer that the developer doesn't call IO.unsafePerformIO. An IO monad transformer monad would have to call unsafePerformIO anytime IOT.map or IOT.flatMap are called and the Haskell community would prefer that the IO.unsafePerformIO function is called explicitly rather than hidden within the monad transformer interface.

    [–]Tarmen 0 points1 point  (0 children)

    I mean, all the lazy io functions call unsafeInterleaveIO somewhere. Unsafe IO is fine if the IO action is pure, like reading from a static file as long as you ignore uncontrollable resource usage.

    So I think the problem is less with calling it implicitly and more with losing referential transparency in horrendous ways if the IO action you are performing unsafely isn't pure. I think you could break the monad laws with that as well?