I have following code snippet from haskell book:
embedded' :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded' = MaybeT (ExceptT (ReaderT (const (return (Right (Just 1))))))
The type signature of ExceptT is as follow:
newtype ExceptT e m a =
ExceptT { runExceptT :: m (Either e a)) }
Compare the type signature of the embedded' function with ExceptT type constructor:
ExceptT e m a
| | |
MaybeT (ExceptT String (ReaderT () IO) (**missing here**) ) Int
How can I just leave ExceptT as higher kinded?
I tried also:
fullType :: ExceptT String []
fullType = undefined
the compiler complains:
* Expecting one more argument to `ExceptT String []'
Expected a type, but `ExceptT String []' has kind `* -> *'
* In the type signature:
fullType :: ExceptT String []
Failed, modules loaded: none.
You probably got confused by outmost MaybeT. This type is parametrised by 2 arguments of kinds m :: * -> * and a :: *, respectively. So, that ExceptT String (ReaderT () IO) is indeed missing an a because it is an MaybeT first argument and should be of kind * -> *. Had we apply Int to ExceptT, it would turn into * and then it can't be passed to MaybeT.
Disclaimer: I am not with my Haskell environment, so this might be utter nonsense.
Put in an explicit type variable for the missing spot on ExceptT:
embedded' :: MaybeT (ExceptT String (ReaderT () IO) a) Int
embedded' = MaybeT (ExceptT (ReaderT (const (return (Right (Just 1))))))
Hopefully the compiler can figure out what a should be!
What you're running into, which shows more obviously in your fullType example, is that it's not possible to give something a type of kind * -> *. Functions, values and so forth all need to have types of kind *.
Currying a type constructor gives you a * -> *, so you have to provide something for all the parameters.
Putting a type parameter in the signature for embedded' makes it kind *, but polymorphic over a.
Related
I've got this type alias:
type Board a = ReaderT String (StateT String IO) a
I know that StateT has the kind * -> (* -> *) -> * -> * so it should get three parameters. But in the above example, StateT only receives String and the IO-Monad.
Now I'm wondering where the missing parameter is passed to StateT.
Same goes for IO which should get one parameter but doesn't get any.
If you look at the definition of ReaderT, you will see that its second parameter is itself applied to its last parameter:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
^^^
right here
Which means that its second parameter m must have kind m :: * -> *. And this is exactly what you get if you apply only two, not three, parameters to StateT:
StateT :: * -> (* -> *) -> * -> *
StateT x y :: * -> *
(where x :: * and y :: * -> *)
When substituting the definition of ReaderT in your type Board, you'll get:
(1) type Board a = ReaderT String (StateT String IO) a
-- Substituting ReaderT definition (pseudocode)
(2) type Board a = { runReaderT :: String -> StateT String IO a }
^^^^^^^^^^^^^^^^^^
Look, StateT has all its three parameters!
You correctly observe that
StateT has the kind * -> (* -> *) -> * -> *
and the same is true of ReaderT.
So it takes 3 "parameters" as you call them. The first is String, of kind *, and the third is a, again of kind *. While the second must be of kind * -> *.
And that is given in your example by StateT String IO. So although there is in one sense a "missing parameter" of StateT, this needs to be "missing" in order to get something of kind * -> * - if you tried something like type Board a = ReaderT String (StateT String IO Int) a, this would fail with a "kind error", precisely because ReaderT's second type argument needs to be of kind * -> *, not of kind * which StateT String IO Int would have.
The same applies to why IO is used on its own rather than something of the form IO a. StateT String (IO Int) wouldn't work because StateT needs to apply to something of kind * -> * as its second type argument - IO has this kind but IO Int (or anything of the form IO a) does not.
To take a step back, monad transformers like ReaderT and StateT transform another monad, and a monad must always be of kind * -> *. IO is a monad, and so is StateT String IO. But IO Int and StateT String IO Int are not monads - and not for failing the monad laws or anything like that, but for a much more fundamental meaning, they are the wrong kind. (They are "concrete types" - types which have values - rather than "type constructors" that take another type as an argument.)
How come the following
foo :: MonadIO m => m ()
foo = print "hi"
causes the following error
Couldn't match type ‘m’ with ‘IO’
‘m’ is a rigid type variable bound by
the type signature for:
foo :: forall (m :: * -> *). MonadIO m => m ()
at foo.hs:57:8
Expected type: m ()
Actual type: IO ()
As far as I know, shouldn't the MonadIO constraint allow this to work since IO () should be equal to a MonadIO ?
IO is not equal to MonadIO.
MonadIO is a typeclass that, in plain terms, means that the monad in question can perform IO operations. In practice, since IO monad is "magic", this can mean only one of two things: the monad in question is IO itself, or the monad in question wraps IO in some way.
To express this idea of wrapping, the MonadIO type class has a method liftIO :: IO a -> m a, which lets you take an IO operation and "lift" it (or, if you prefer, "wrap" it) into the monad m, whatever that is.
So, to fix your code, all you need is liftIO:
foo :: MonadIO m => m ()
foo = liftIO $ print "hi"
I have following code snippet from the haskellbook that shows step by step, how monad transformer is going to unwrap:
module OuterInner where
import Control.Monad.Trans.Except
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
-- We only need to use return once
-- because it's one big Monad
embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded = return 1
maybeUnwrap :: ExceptT String (ReaderT () IO) (Maybe Int)
maybeUnwrap = runMaybeT embedded
-- Next
eitherUnwrap :: ReaderT () IO (Either String (Maybe Int))
eitherUnwrap = runExceptT maybeUnwrap
-- Lastly
readerUnwrap :: () -> IO (Either String (Maybe Int))
readerUnwrap = runReaderT eitherUnwrap
There is an exercise, that I have to wrap everything again:
embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded = ??? (const (Right (Just 1)))
I tried as follows:
embedded' :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded' = MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
but the compiler complains:
D:\haskell\chapter26\src\OuterInner.hs:24:15: error:
* Couldn't match type `Either a0' with `IO'
Expected type: MaybeT (ExceptT String (ReaderT () IO)) Int
Actual type: MaybeT (ExceptT String (ReaderT () (Either a0))) Int
* In the expression:
MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
In an equation for embedded':
embedded' = MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
D:\haskell\chapter26\src\OuterInner.hs:24:32: error:
* Couldn't match type `Maybe Integer'
with `Either String (Maybe Int)'
Expected type: ReaderT () (Either a0) (Either String (Maybe Int))
Actual type: ReaderT () (Either a0) (Maybe Integer)
* In the first argument of `ExceptT', namely
`(ReaderT (const (Right (Just 1))))'
In the first argument of `MaybeT', namely
`(ExceptT (ReaderT (const (Right (Just 1)))))'
In the expression:
MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
Failed, modules loaded: none.
How to solve the exercise?
GHC typed holes extension to the rescue! It lets you plumb a _ somewhere in your expression and make GHC tell you needed type. So, let's start with
:t MaybeT (ExceptT (ReaderT (const _)))
<interactive>:1:33: error:
* Found hole: _ :: m (Either e (Maybe a))
Now we need a value of ReaderT () (Either e (Maybe a)). Plumbing _ over and over we finally arrive at value
embedded = MaybeT (ExceptT (ReaderT (const (return (Right (Just 1))))))
You have defined a MaybeT (ExceptT String (Reader ())) Int. You've missed the innermost layer, IO. Unlike the others, IO doesn't have a concrete representation, but you can of course inject pure values into it with return or pure (duh).
embedded' = MaybeT . ExceptT . ReaderT
$ (pure .) . const . Right $ Just 1
I don't understand why this code typechecks:
error1 :: ErrorT String (ReaderT Int IO) Int
error1 = asks id
fyi, the asks has this type:
asks :: Monad m => (r -> a) -> ReaderT r m a
On the other hand, I'm able to understand, that this code typechecks:
reader1 :: ReaderT Int IO Int
reader1 = asks id
id has type a -> a and there is an instance of Monad for IO, so the compiler can infer the type. That's clear for me.
The ErrorT is newtype and haskell spec states, (in the section about newtypes):
... it creates a distinct type that must be explicitly coerced to or
from the original type ...
According to my interpretation, I should be able to get the same type as in error1 only explicitly, with some coercion similar to this:
reader2 :: ReaderT Int IO (Either String Int)
reader2 = fmap (\i -> Right i) reader1
error2 :: ErrorT String (ReaderT Int IO) Int
error2 = ErrorT reader2
But, apparently, since the error1 typechecks just fine, there is some knowledge hidden from me. Can You help uncovering it for me?
The imports needed for running the example code:
import Control.Monad.Error (ErrorT(ErrorT))
import Control.Monad.Reader (ReaderT, asks)
The function asks is exported by two related modules with slightly different types. The version from Control.Monad.Trans.Reader (part of the transformers package), has the type given in the question:
asks :: Monad m => (r -> a) -> ReaderT r m a
However, the version used seems to be the one in the mtl package, from the Control.Monad.Reader module, which has the following, more general, type:
asks :: MonadReader r m => (r -> a) -> m a
So the example definition
error1 :: ErrorT String (ReaderT Int IO) Int
error1 = asks id
means that
MonadReader Int (ErrorT String (ReaderT Int IO))
must hold.
Also defined by mtl are the following instances for MonadReader:
instance Monad m => MonadReader r (ReaderT r m)
instance (Error e, MonadReader r m) => MonadReader r (ErrorT e m)
With these, the constraint above reduces to
(Error String, Monad IO)
which both hold as well.
I think part of your answer is that the monadic functions like asks, put, get, throwError, etc. in the mtl package are written to automatically lift themselves depending on how the monad stack is evaluated.
For example, the following function:
foo = do a <- asks id
if a < 0 then throwError "oops"
else return $ sqrt a
can have both of the types:
ErrorT String (ReaderT Double m) Double
ReaderT (ErrorT String m Double) Double
depending on the order in which runReaderT and runErrorT are run.
The most general type of this function is:
foo :: (MonadError [Char] m, MonadReader b m, Ord b, Floating b) => m b
which shows there is no a priori ordering to the monad layers.
In your example you gave a type signature which says that there is an ErrorT layer in your monad even though you didn't use the throwError function. That's just equivalent to adding the MonadError [Char] m constraint to the type signature.
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.