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.
Related
I just managed to understand the definition of the class MonadReader
class Monad m => MonadReader r m | m -> r where
...
After reading the document of Functional Dependency in Haskell, now I can understand that | m -> r specifies that type variable r is uniquely decided by m. I think this requirement is reasonable based on the few typical instances of MonadReader I have seen so far (e.g. Reader), but it seems to me that we can still define instances like Reader even without this functional dependency clause.
My question is why we need functional dependency in the definition of MonadReader? Is this functionally necessary for defining MonadReader in a sense that MonadReader cannot be properly defined without it, or it is merely a restriction to limit the ways how MonadReader can be used so that the instances of MonadReader will all behave in a certain expected way?
It is needed to make type inference work in a way which is more convenient to the user.
For example, without the fundep this would not compile:
action :: ReaderT Int IO ()
action = do
x <- ask
liftIO $ print x
To make the above compile we would need to write
action :: ReadertT Int IO ()
action = do
x <- ask :: ReadertT Int IO Int
liftIO $ print x
This is because, without the fundep, the compiler can not infer that x is an Int. After all a monad ReadertT Int IO might have multiple instances
instance MonadReader Int (ReaderT Int IO) where
ask = ReaderT (\i -> return i)
instance MonadReader Bool (ReaderT Int IO) where
ask = ReaderT (\i -> return (i != 0))
instance MonadReader String (ReaderT Int IO) where
ask = ReaderT (\i -> return (show i))
-- etc.
so the programmer must provide some annotation which forces x :: Int, or the code is ambiguous.
This is not really an answer, but it's much too long for a comment. You are correct that it's possible to define the MonadReader class without a fundep. In particular, the type signature of each method determines every class parameter. It would be quite possible to define a finer hierarchy.
class MonadReaderA r m where
askA :: m r
askA = readerA id
readerA :: (r -> a) -> m a
readerA f = f <$> askA
-- This effect is somewhat different in
-- character and requires special lifting.
class MonadReaderA r m => MonadReaderB r m where
localB :: (r -> r) -> m a -> m a
class MonadReaderB r m
=> MonadReader r m | m -> r
ask :: MonadReader r m => m r
ask = askA
reader
:: MonadReader r m
=> (r -> a) -> m a
reader = readerA
local
:: MonadReader r m
=> (r -> r) -> m a -> m a
local = localB
The main problem with this approach is that users have to write a bunch of instances.
I think the source of confusion is that in the definition of
class Monad m => MonadReader r m | m -> r where
{- ... -}
It is implicitly asumed that m contains r itself (for common instances). Let me use a lighter definiton of Reader as
newtype Reader r a = Reader {runReader :: r -> a}
When the r parameter is chosen you can easely define a monad instance for Reader r. That means that in the type class definition m should be substitute for Reader r. So take a look at how the expresion ends up being:
instance MonadReader r (Reader r) where -- hey!! r is duplicated now
{- ... -} -- The functional dependecy becomes Reader r -> r which makes sense
But why do we need this?. Look at the definition of ask within the MonadReader class.
class Monad m => MonadReader r m | m -> r where
ask :: m r -- r and m are polymorphic here
{- ... -}
Without the fun-dep nothing could stop me for defining ask in a way to return a different type as the state. Even more, I could define many instances of monad reader for my type. As an example, this would be valid definitions without func-dep
instance MonadReader Bool (Reader r) where
-- ^^^^ ^
-- | |- This is state type in the user defined newtype
-- |- this is the state type in the type class definition
ask :: Reader r Bool
ask = Reader (\_ -> True) -- the function that returns True constantly
{- ... -}
instance MonadReader String (Reader r) where
-- ^^^^^^ ^
-- | |- This is read-state type in the user defined newtype
-- |- this is the read-state type in the type class definition
ask :: Reader r String
ask = Reader (\_ -> "ThisIsBroken") -- the function that returns "ThisIsBroken" constantly
{- ... -}
So if I had a value val :: ReaderT Int IO Double what would be the result of ask. We'd need to specify a type signature as below
val :: Reader Int Double
val = do
r <- ask :: Reader Int String
liftIO $ putStrLn r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
"ThisIsBroken"
1.0
val :: Reader Int Double
val = do
r <- ask :: Reader Int Bool
liftIO $ print r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
True
1.0
Aside from being senseless, it is unconvinient to be specifiying the type over and over.
As a conclusion using the actual definition of ReaderT. When you have something like val :: ReaderT String IO Int the functional dependency says Such a type might have only one single instance of MonadReader typeclass which is defined to be the one that uses String as r
I was trying to write my own monad transformers where it would make sense to have multiple of the same monad transformer on the stack with different types. The issue can be illustrated with the reader monad.
The reader monad is offered as a way to hold a read only context of a given type
ex1 :: Reader Bool Bool
ex1 = ask
or
ex2 :: Reader Char Bool
ex2 = pure True
monad transformers allow less restrictive assumptions about the underlining monad
ex3 :: (MonadReader Bool m) => m Bool
ex3 = ask
However, what if I want to have more than 1 read only environment? I can write a function like
ex4 :: (MonadReader Bool m, MonadReader Char m) => m Bool
ex4 = ask
However, as far as I can tell, there is no way to run ex4 since
class Monad m => MonadReader r m | m -> r
means that each MonadReader has a unique reading type. Is there a standard work around for multiple transformers on the same stack? Should I try to avoid this entirely?
Use a transformer and lift to get to your inner monad:
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Class (lift)
type MyMonad a = ReaderT Bool (Reader Char) a
askBool :: MyMonad Bool
askBool = ask
askChar :: MyMonad Char
askChar = lift ask
The code you presented didn't use any monad transformer (directly). It used the reader monad (which happens to be a transformer applied to the identity monad) and the MonadReader type class. As you noticed, the type function implied by MonadReader can't result in two different outputs (the environment types) for the same input (the monad m).
One way to deal with it in a relatively straightforward way is to create a type that represents the state you wanna keep track of. Say you want to keep track of both a Bool and a Char as in your example
data MyState = MyState { getBool :: Bool, getChar :: Char }
f :: MonadReader MyState m => m Bool
f = asks getBool
Others may have more advanced solutions!
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.
I'm pulling together code from a number of different places, and I'm trying to deal with the following:
Problem
I have a transformer stack with the following simplified type:
action :: m (ReaderT r IO) a
and I'm trying to use the action in the context of a different stack, which has a different reader environment:
desired :: m (ReaderT r' IO) a
I can of course provide
f :: r' -> r
Example
things :: m (ReaderT r' IO) ()
things = do
-- ... some stuff
-- <want to use action here>
action :: m (ReaderT r IO) a -- broken
-- ... more stuff
pure ()
What I've considered
withReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a
This has the problem that ReaderT is the outer monad, whilst I want to use it on an inner one.
I've also considered that this might be related to MonadBase or MonadTransControl, but I'm not familiar with their workings.
I don't think it's possible to write a function with signature:
changeReaderT :: (MonadTrans m)
=> (r -> r')
-> m (ReaderT r IO) a
-> m (ReaderT r' IO) a
the issue being that the only operation possible, in general, on the second argument is lifting it to t (m (ReaderT r IO)) a for some monad transformer t, which doesn't buy you anything.
That is, the MonadTrans m constraint alone doesn't provide enough structure to do what you want. You either need m to be an instance of a typeclass like MFunctor in the mmorph package that allows you to modify an inner layer of the monad stack in a general way by providing a function like:
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b
(which is what #Juan Pablo Santos was saying), or else you need an ability to dig into the structure of your m monad transformer to partially run and rebuild it (which will be transformer-specific).
The first approach (using hoist from the mmorph package) will be most convenient if your m is already made up of transformers supported by the mmorph package. For example, the following typechecks, and you don't have to write any instances:
type M n = MaybeT (StateT String n)
action :: M (ReaderT Double IO) a
action = undefined
f :: Int -> Double
f = fromIntegral
desired :: M (ReaderT Int IO) a
desired = (hoist $ hoist $ withReaderT fromIntegral) action
You'll need a hoist for each layer in M.
The second approach avoids hoist and requisite MFunctor instances but requires tailoring to your specific M. For the above type , it looks something like:
desired' :: M (ReaderT Int IO) a
desired' = MaybeT $ StateT $ \s ->
(withReaderT fromIntegral . flip runStateT s . runMaybeT) action
You basically need to run the monad down to the ReaderT layer and then rebuild it back up, treating layers like StateT with care. This is exactly what the MFunctor instances in mmorph are doing automatically.
While building a monad stack with monad transformers to write a library, I hit a question about the behavior of it.
The following code won't pass the type checker:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Foo (FooM, runFooM, foo) where
import Control.Applicative
import Control.Monad.Reader
newtype FooM m a = FooM { runFooM :: ReaderT Int m a }
deriving (Functor, Applicative, Monad, MonadReader Int)
foo :: FooM m Int
foo = do
x <- ask
return x
The error is:
$ ghc foo.hs
[1 of 1] Compiling Foo ( foo.hs, foo.o )
foo.hs:12:3:
No instance for (Monad m) arising from a do statement
Possible fix:
add (Monad m) to the context of
the type signature for foo :: FooM m Int
In a stmt of a 'do' block: x <- ask
In the expression:
do { x <- ask;
return x }
In an equation for ‘foo’:
foo
= do { x <- ask;
return x }
The fix is easy as GHC suggests, just adds Monad constraint to the foo function:
foo :: Monad m => FooM m Int
foo = do
x <- ask
return x
But here, the foo function only asks the FooM value to give its Int value and it is already an (automatically derived) MonadReader instance.
So I think Monad constraint is not required to m.
I guess this relates to the implementation of the monad transformers (I use mlt==2.2.1),
but I cannot figure out the exact reason.
I may miss something obvious though.
Could you explain why this doesn't pass the checker?
Thanks.
It's because the Monad instance for ReaderT is defined as
instance Monad m => Monad (ReaderT r m)
i.e. the type ReaderT r m is an instance of Monad only if the inne rm is an instance of Monad. That's why you cannot have an unconstrained m when using the Monad instance of ReaderT (which your FooM type is using via the deriving mechanism).
returns type is Monad m => a -> m a, hence the need for the constraint.
By the monad laws, foo ≡ ask, which will indeed work without the Monad constraint. But if you don't require Monad, then GHC can hardly make simplifications based on these laws, can it? Certainly not before type checking the code. And what you wrote is syntactic sugar for
foo = ask >>= \x -> return x
which requires both (>>=) :: Monad (FooM m) => FooM m Int -> (Int->FooM m Int) -> FooM m Int and return :: Monad (FooM m) => Int->FooM m Int.
Again, the >>= return does nothing whatsoever for a correct monad, but for a non-monad it isn't even defined and can thus not just be ignored.