I'm following a monad transformers tutorial here.
At this point in the tutorial, it asks me to try to implement the Monad instance for the EitherIO
data type, defined as:
data EitherIO e a = EitherIO {
runEitherIO :: IO (Either e a)
}
So I tried:
instance Functor (EitherIO e) where
fmap f = EitherIO . fmap (fmap f) . runEitherIO
instance Monad (EitherIO e) where
return = EitherIO . return . Right
x >>= f = join $ fmap f x
The tutorial's version was a bit different:
instance Monad (EitherIO e) where
return = pure -- the same as EitherIO . return . Right
x >>= f = EitherIO $ runEitherIO x >>= either (return . Left) (runEitherIO . f)
Now, the types all fit, so I thought I was good, and congratulated myself on finally finding a use for join
.
As it turns out, further down the tutorial, I was asked to run runEitherIO getToken
on the following:
liftEither x = EitherIO (return x)
liftIO x = EitherIO (fmap Right x)
getToken = do
liftIO (T.putStrLn "Enter email address:")
input <- liftIO T.getLine
liftEither (getDomain input)
Using my version of the >>=
operator, GHCi would hang after I provided some input. Then even after I interrupt via ^C
, GHCi would start acting strangely, hanging for a second or two while I'm typing. I'd have to kill GHCi to restart. When I replaced the >>=
definition with the tutorial definition, everything worked.
My full file is here.
So:
What is wrong with my definition?
Why would GHCi typecheck and then behave like it did? Is this a GHCi bug?
My guess is that this is the culprit:
instance Monad (EitherIO e) where
return = EitherIO . return . Right
x >>= f = join $ fmap f x
However, join
is defined as:
join x = x >>= id
However, in this way join
and >>=
get defined in a mutually recursive way which leads to non termination.
Note that this type checks, much as the following does:
f, g :: Int -> Int
f x = g x
g x = f x
Bottom line: you should provide a definition for >>=
which does not involve join
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With