I was trying to write some EitherT monad transformer, as suggested from real world haskell chapter 18.
newtype EitherT e m a = EitherT {
runEitherT :: m (Either e a)
}
my EitherT will have Left error and Right result for its Either type, and will bind all computation that yields Right values while stopping at left values, keeping them as error.
my code is below(sorry for the imperative style):
bindET :: (Monad m) => (EitherT e m a) -> (a -> EitherT e m b) -> (EitherT e m b)
x `bindET` f = EitherT $ do
mx <- runEitherT x
case mx of
Right success -> runEitherT (f success)
Left error -> return (Left error)
instance (Monad m) => Monad (EitherT e m) where
return a = EitherT $ return (Right a)
(>>=) = bindET
fail e = EitherT $ return (Left e)
I thought writing Monad instances for EitherT transformer was quite simple, however I get this cryptic error message when I load the code into ghci:
EitherT.hs:30:18:
Could not deduce (e ~ [Char])
from the context (Monad m)
bound by the instance declaration at EitherT.hs:27:10-41
`e' is a rigid type variable bound by
the instance declaration at EitherT.hs:27:10
Expected type: EitherT e m a
Actual type: EitherT String m a
In the expression: EitherT $ return (Left e)
In an equation for `fail': fail e = EitherT $ return (Left e)
In the instance declaration for `Monad (EitherT e m)'
Failed, modules loaded: none.
it seems fail function is fixed to take String as an argument - well, if that's the case then my EitherT e m a will be EitherT String m a and all the Left values will be Left String. but I want EitherT monad to take any types of value as Left to indicate errors in computation. How can I achieve that?
EitherT is also an instance of MonadError, giving you throwError :: e -> EitherT e m a. If you are implementing your own EitherT for educational reasons, you can look up MonadError at the link above and figure out how to make your own ErrorT type also an instance of that.
fail is generally considered a poor interface, because a, it is tied to String as you noticed and b, because it is in Monad, forcing monads to implement it even when it doesn't make sense.
If you want to use fail in that way, you can define the monad as EitherT String m:
instance (Monad m) => Monad (EitherT String m) where
-- ...
This is not as useless as it looks, since errors are usually strings anyway.
The benefit of doing it this way is that you can handle pattern match failures. This could be handy if you want to (for example) call an action that needs to return Just
do
Just a <- lift getTheThing
lift (print a)
The downside is you get a less-than-useful error message "pattern match failure in ..." rather than something like "couldn't get the thing, try restarting the server".
If you just want to have something to call manually on failure though, use throwError like Cactus suggests.
Related
How to convert StateT g (Either E) T to ExceptT E (StateT g Identity) T?
Probably, some mix of traverse and hoist could be useful here.
You can't exchange an arbitrary pair of monads. But you can exchange these two particular monads. It's easiest to understand if you expand the newtypes in the definitions of those monad transformers.
Given
newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }
and
newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }
expanding the newtypes in your first type expression gives us the isomorphism
StateT s (Either e) a <-> s -> Either e (s, a)
whereas for the second we get
ExceptT e (StateT s Identity) a <-> s -> (s, Either e a)
Note that Either e (s, a) may or may not contain an s, whereas (s, Either e a) always does. Now, one can go from the latter to the former just by traverseing the tuple inside the function, but going the other way requires some domain-specific reasoning: if the computation throws an error then we should plumb the state through unchanged to the catcher of the error. (Is this the right thing to do? I find it rather debatable.)
stateTEitherToExceptTState :: (s -> Either e (s, a)) -> (s -> (s, Either e a))
stateTEitherToExceptTState f s =
case f s of
Left e -> (s, Left e)
Right sa -> fmap Right sa
newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
instance (Monad m, Error e) => Monad (ErrorT e m) where
m >>= k = ErrorT $ do
a <- runErrorT m
case a of
Left l -> return (Left l)
Right r -> runErrorT (k r)
ErrorT is just a value constructor ( type constructor as well) and to get instance of that type ( to get ErrorT value ) we have to call constructor with one parameter- a function ( destructor) which gets ErrorT and returns inner monad, in our case it is any m (Either e a). So, in bind function it is defined: m >>= k = ErrorT $ .... But, in its definion it calls runErrorT which is just definied. So something like recursive call. But, I suppose that there is no recursion here. That means that I misunderstand something with monad/ monad transformers. Please help :)
I think you are confused by the newtype wrapper. The newtype definition of ErrorT results in two functions being defined:
ErrorT :: m (Either e a) -> ErrorT e m a
runErrorT :: ErrorT e m a -> m (Either e a)
so in the definition of (>>=), ErrorT $ do ... refers to the constructor for the ErrorT newtype while
a <- runErrorT m
runErrorT (k r)
refer to the 'unwrapping' function to extract the underlying m (Either e a).
Let's look at:
instance (Error e) => MonadTrans (ErrorT e) where
lift m = ErrorT $ do
a <- m
return (Right a)
I cannot understand why is necessary a <- m. Why we don't write just:
instance (Error e) => MonadTrans (ErrorT e) where
lift m = ErrorT $ do
return (Right m)
You're reading a <- m as "assign a the value m." That notation for assignment is common in pseudocode, but it means something different in Haskell. You can read it as "Produce a value from m and bind that value to a." To be more precise, in a do block,
a <- m
...
...
is equivalent to
m >>= \a ->
do
...
...
So applying Right to a is sensible, but applying it to m gives you a monadic action wrapped in Either, which isn't usually what you're after.
There is, however, a shorter way to write that instance:
instance Error e => MonadTrans (ErrorT e) where
lift m = ErrorT (Right <$> m)
Nota Bene: ErrorT has generally been supplanted by the more generally-useful ExceptT, which doesn't have the annoying and often-irrelevant Error context. In particular, it's very often useful to have an "exception" value that doesn't actually represent an error and isn't an instance of Show.
m :: m a
Right m :: Either e (m a)
return (Right m) :: m (Either e (m a))
ErrorT $ return (Right m) :: ErrorT e m (m a)
This has the wrong type: we wanted ErrorT e m a.
Instead, when using a <- m, we have:
a :: a
Right a :: Either e a
return (Right a) :: m (Either e a)
ErrorT $ return (Right a) :: ErrorT e m a
which is OK.
(Above some value variables have the same name of type variables on the right of :: -- this is just an incident.)
Alternatives:
instance (Error e) => MonadTrans (ErrorT e) where
lift m = ErrorT $ fmap Right m
or with applicative notation,
instance (Error e) => MonadTrans (ErrorT e) where
lift m = ErrorT $ Right <$> m
How does Haskell know which is correct monad instance for each return expression?
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . return
It's actually unambiguous from the context.
Let's play the typechecker,
-- From the signature
MaybeT . return . return :: a -> MaybeT a
-- From the type of MaybeT
return . return :: a -> m (Maybe a)
-- From the type of `.`
(return :: Maybe a -> m a) . (return :: a -> Maybe a)
And once we have the type of each return, the "instance selection algorithm" will correctly choose the first to use ms return and the second to be Maybe.
It infers the needed types.
It's clear from the meaning of an instance definition that we're trying to define
returnMaybeT :: Monad m => a -> MaybeT m a
returnMaybeT x = MaybeT (return (return x))
Since MaybeT :: m (Maybe a) -> MaybeT a (taken as a function) we know that the inner stack of returns must have type
return (return x) :: Monad m => a -> m (Maybe a)
Now, we know that return is a polymorphic function which has a type like
return :: a -> n a
for any Monad n. In the case of this first return, the Monad m => constraint tells us that m is a Monad and so we can use its definition of return. This lets us get all the way down to the inner return
return x :: a -> Maybe a
and since we know that Maybe has a Monad instance we can use the return from that.
Ultimately, all the compiler has to do is whittle its way down the expression trying to determine the types needed at each return. After it determines the needed type it has to check to see if it knows a Monad instance for that type. This is simple for Maybe, since it's concrete, but a little more difficult to see for m since it's just a variable.
The reason m works is because we've constrained the variable to certainly be some type which instantiates Monad.
I'm trying to create a monad transformer for a future project, but unfortunately, my implementation of the Monad typeclasse's (>>=) function doesn't work.
First of all, here is the underlying monad's implementation :
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
Here, the implementation of the Monad typeclasse is done automatically by GHC (using the GeneralizedNewtypeDeriving language pragma).
The monad transformer is defined as so :
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
The problem comes from the way I instanciate the (>>=) function of the Monad typeclasse :
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
The way I see it, the first >>= runs in the underlying m monad. Thus, runRuntimeT x >>= returns a value of type Runtime a (right ?). Then, the following code, id >>=, should return a value of type a. This value is the passed on to the function f of type f :: (Monad m) => a -> RuntimeT m b.
And here comes the type problem : the f function's type doesn't match the type required by the (>>=) function. Jow can I make this coherent ? I can see why this doesn't work, but I can't manage to turn it into something functionnal.
Edit : The error message :
Core.hs:34:4:
Occurs check: cannot construct the infinite type: m = RuntimeT m
When generalising the type(s) for `>>='
In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.
Thank you for you help, and do not hesitate to correct any flaws in my message,
Charlie P.
The usual StateT s m monad sends a to s -> m (a, s) but you are working with m (s -> (a, s)) instead. I don't think the latter forms a monad for general s. Are you sure you don't just want to use StateT?
Here's why I don't think a → m (s -> (a, s)) is a monad: To write >>= I need a function that takes arguments of types
m (s -> (a, s))
a -> m (s -> (b, s))
and returns a value of type
m (s -> (b, s))
The "effects" (i.e. fmap (const ())) of the result must be those of the first argument, since we have no way to get an a to pass to the second argument. Since m appears only on the outside of the result type, we then cannot use the second argument for anything at all—there will be no way to get rid of the m it introduces.
To follow on from what Reid Barton said about StateT - here's how you would define RuntimeT using StateT. The Runtime monad can then be trivially defined using the identity monad.
newtype RuntimeT m a = R {
unR :: StateT EInfo m a
}
type Runtime = RuntimeT Identity
instance Monad m => Monad (RuntimeT m) where
return = R . return
(R m) >>= f = R (m >>= unR . f)