I know with the data constructor and the run*** function,
I can lift any function to a specific MonadTrans instance.
Like this,
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad
liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f x = MaybeT $ do
inner <- runMaybeT x
return $ liftM f inner
But how can I generalize this liftF to
liftF :: (MonadTrans t, Monad m) => (a -> b) -> t m a -> t m b
As #thoferon mentioned, you can just use liftM:
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad (liftM)
liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f m = liftM f m
liftF' :: (MonadTrans t, Monad m, Monad (t m)) => (a -> b) -> t m a -> t m b
liftF' f m = liftM f m
(I had to add an additional Monad constraint to liftF').
But why would you do this? Check out the source code for MaybeT -- there's already a Monad instance:
instance (Monad m) => Monad (MaybeT m) where
fail _ = MaybeT (return Nothing)
return = lift . return
x >>= f = MaybeT $ do
v <- runMaybeT x
case v of
Nothing -> return Nothing
Just y -> runMaybeT (f y)
And actually, as liftM is the same as Functor's fmap:
instance (Functor m) => Functor (MaybeT m) where
fmap f = mapMaybeT (fmap (fmap f))
You can find similar instances for all the transformers.
Is this what you are asking? Can you provide some more concrete examples that show what you're trying to do and why, and in what way the existing Functor and Monad instances fail to meet your needs?
Related
I have a function that apply a function to a file if it exists:
import System.Directory
import Data.Maybe
applyToFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFile f p = doesFileExist p >>= apply
where
apply True = f p >>= (pure . Just)
apply False = pure Nothing
Usage example:
applyToFile readFile "/tmp/foo"
applyToFile (\p -> writeFile p "bar") "/tmp/foo"
A level of abstraction can be added with:
import System.Directory
import Data.Maybe
applyToFileIf :: (FilePath -> IO Bool) -> (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFileIf f g p = f p >>= apply
where
apply True = g p >>= (pure . Just)
apply False = pure Nothing
applyToFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFile f p = applyToFileIf doesFileExist f p
That allow usages like:
applyToFileIf (\p -> doesFileExist p >>= (pure . not)) (\p -> writeFile p "baz") "/tmp/baz"
I have the feeling that I just scratched the surface and there is a more generic pattern hiding.
Are there better abstractions or more idiomatic ways to do this?
applyToFileIf can be given a more generic type and a more generic name
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
applyToIf f g p = f p >>= apply
where
apply True = g p >>= (return . Just)
apply False = return Nothing
In the type of applyToIf we see the composition of two Monads
Maybe is a monad ---v
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
^------------- m is a monad -------------^
When we see the composition of two monads, we can expect that it could be replaced with a monad transformer stack and some class describing what that monad transformer adds. The MaybeT transformer replaces m (Maybe a)
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
And adds MonadPlus to what an m can do.
instance (Monad m) => MonadPlus (MaybeT m) where ...
We'll change the type of applyToIf to not have a composition of two monads and instead have a MonadPlus constraint on a single monad
import Control.Monad
applyToIf :: MonadPlus m => (a -> m Bool) -> (a -> m b) -> a -> m b
applyToIf f g p = f p >>= apply
where
apply True = g p
apply False = mzero
This could be rewritten in terms of guard from Control.Monad and given a more generic name.
guardBy :: MonadPlus m => (a -> m Bool) -> (a -> m b) -> a -> m b
guardBy f g p = f p >>= apply
where
apply b = guard b >> g p
The second g argument adds nothing to what guardBy can do. guardBy f g p can be replaced by guardBy f return p >>= g. We will drop the second argument.
guardBy :: MonadPlus m => (a -> m Bool) -> a -> m a
guardBy f p = f p >>= \b -> guard b >> return p
The MaybeT transformer adds possible failure to any computation. We can use it to recreate applyToIf or use it more generally to handle failure through complete programs.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
applyToIf f g = runMaybeT . (>>= lift . g) . guardBy (lift . f)
If you instead rework the program to use monad style classes, it might include a snippet like
import Control.Monad.IO.Class
(MonadPlus m, MonadIO m) =>
...
guardBy (liftIO . doesFileExist) filename >>= liftIO . readFile
I've defined my own monad transformer:
data Config = Config { ... }
data State = State { ... }
newtype FooT m a = FooT {
runFoo :: ReaderT Config (StateT State m) a
} deriving (Functor, Monad, MonadReader Config, MonadState State)
And I've defined a MonadTrans instance for it.
instance MonadTrans FooT where
lift = FooT . lift . lift
Now, I have various monads that I can't just have be derived for me by the compiler. I'll take MonadIO as the example. So I've defined my MonadIO instance as
instance MonadIO m => MonadIO (FooT m) where
liftIO = lift . liftIO
However, I find that I'm doing a lot of lifting, for each Monad. Why could the author of each Monad typeclass (i.e. MonadIO, MonadCatchIO, MonadFoo) not define a general instance in terms of MonadTrans, instead of making me implement an instance for each new MonadTrans I come up with? a la
instance (MonadIO m, MonadTrans t, Monad (t m)) => MonadIO (t m) where
liftIO = lift . liftIO
That requires UndecidableInstances to compile, and I'm not certain that it's correct (in fact, pretty sure it's incorrect), but serves to express my intent for now.
So, is this possible? If not, why not? Will it ever be?
Let's say that I've come up with an alternative to MonadIO, called
MyMonadIO. It's like MonadIO in every way, except for the name:
class Monad m => MyMonadIO m where
myLiftIO :: IO a -> m a
Assuming your FooT type:
newtype FooT m a = FooT
{ runFoo :: ReaderT Config (StateT AppState m) a
} deriving (Functor, Applicative, Monad, MonadReader Config, MonadState AppState)
It's possible to create an instance of MyMonadIO for ReaderT,
StateT, and finally FooT. I've added extra type annotations to make it
easier for the reader to figure out what's going on:
instance MyMonadIO m => MyMonadIO (ReaderT r m) where
myLiftIO :: IO a -> ReaderT r m a
myLiftIO = (lift :: m a -> ReaderT r m a) . (myLiftIO :: IO a -> m a)
instance MyMonadIO m => MyMonadIO (StateT s m) where
myLiftIO :: IO a -> StateT s m a
myLiftIO = (lift :: m a -> StateT s m a) . (myLiftIO :: IO a -> m a)
instance MyMonadIO m => MyMonadIO (FooT m) where
myLiftIO :: IO a -> FooT m a
myLiftIO = (lift :: m a -> FooT m a) . (myLiftIO :: IO a -> m a)
It's also possbile to use GeneralizedNewtypeDeriving to easily derive
MyMonadIO for FooT (assuming there are already instances for ReaderT and
StateT):
newtype FooT m a = FooT
{ runFoo :: ReaderT Config (StateT AppState m) a
} deriving (Functor, Applicative, Monad, MyMonadIO, MonadReader Config, MonadState AppState)
If you look at the body of the myLiftIO function for the ReaderT, StateT,
and FooT instances, they are exactly the same: lift . myLiftIO.
Here's a repeat of the question:
Why could the author of each Monad typeclass (i.e. MonadIO, MonadCatchIO,
MonadFoo) not define a general instance in terms of MonadTrans, instead of
making me implement an instance for each new MonadTrans I come up with?
For MyMonadIO, this general instance would be as follows:
instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n) where
myLiftIO :: IO a -> t n a
myLiftIO = (lift :: n a -> t n a) . (myLiftIO :: IO a -> n a)
With this instance defined, you don't need a specific instance for ReaderT,
StateT, or even FooT.
This requires UndecidableInstances. However, the problem with this is not undecidability, but that this instance overlaps some potentially valid instances of MyMonadIO.
For instance, imagine the following datatype:
newtype FreeIO f a = FreeIO (IO (Either a (f (FreeIO f a))))
instance Functor f => Functor (FreeIO f) where
fmap :: (a -> b) -> FreeIO f a -> FreeIO f b
fmap f (FreeIO io) = FreeIO $ do
eitherA <- io
pure $
case eitherA of
Left a -> Left $ f a
Right fFreeIO -> Right $ fmap f <$> fFreeIO
instance Functor f => Applicative (FreeIO f) where
pure :: a -> FreeIO f a
pure a = FreeIO . pure $ Left a
(<*>) :: FreeIO f (a -> b) -> FreeIO f a -> FreeIO f b
(<*>) (FreeIO ioA2b) (FreeIO ioA) = FreeIO $ do
eitherFa2b <- ioA2b
eitherFa <- ioA
pure $
case (eitherFa2b, eitherFa) of
(Left a2b, Left a) -> Left $ a2b a
(Left a2b, Right fFreeIOa) -> Right $ fmap a2b <$> fFreeIOa
(Right fFreeIOa2b, o) -> Right $ (<*> FreeIO (pure o)) <$> fFreeIOa2b
instance Functor f => Monad (FreeIO f) where
(>>=) :: FreeIO f a -> (a -> FreeIO f b) -> FreeIO f b
(>>=) (FreeIO ioA) mA2b = FreeIO $ do
eitherFa <- ioA
case eitherFa of
Left a ->
let (FreeIO ioB) = mA2b a
in ioB
Right fFreeIOa -> pure . Right $ fmap (>>= mA2b) fFreeIOa
You don't necessarily need to understand this FreeIO datatype (especially the Functor, Applicative, and Monad instances). It's enough just to know that this is a valid data type.
(If you're interested, this is just a free monad wrapped around IO.)
It's possible to write a MyMonadIO instance for FreeIO:
instance Functor f => MyMonadIO (FreeIO f) where
myLiftIO :: IO a -> FreeIO f a
myLiftIO ioA = FreeIO (Left <$> ioA)
We can even imagine writing a function using FreeIO:
tryMyLiftIOWithFreeIO :: Functor f => FreeIO f ()
tryMyLiftIOWithFreeIO = myLiftIO $ print "hello"
If you try to compile tryMyLiftIOWithFreeIO with both this instance (MyMonadIO (FreeIO f)) and the bad instance from above, you get the following error:
test-monad-trans.hs:103:25: error:
• Overlapping instances for MyMonadIO (FreeIO f)
arising from a use of ‘myLiftIO’
Matching instances:
instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n)
-- Defined at test-monad-trans.hs:52:10
instance Functor f => MyMonadIO (FreeIO f)
-- Defined at test-monad-trans.hs:98:10
• In the expression: myLiftIO $ print "hello"
In an equation for ‘tryMyLiftIOWithFreeIO’:
tryMyLiftIOWithFreeIO = myLiftIO $ print "hello"
Why does this happen?
Well, in instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n), what is the kind of t and n?
Since n is supposed to be a Monad, it's kind is * -> *. And since t is a monad transformer, it's kind is (* -> *) -> * -> *. t n is also supposed to be a Monad, so it's kind is also * -> *:
n :: * -> *
t :: (* -> *) -> * -> *
t n :: * -> *
Now, in instance Functor f => MyMonadIO (FreeIO f), what are the kinds of FreeIO and f?
f is supposed to be a Functor, so it's kind is * -> *. FreeIO's kind is (* -> *) -> * -> *. FreeIO f is a Monad, so it's kind is * -> *:
f :: * -> *
FreeIO :: (* -> *) -> * -> *
FreeIO f :: * -> *
Since the kinds are the same, you an see that instance Functor f => MyMonadIO (FreeIO f) overlaps with instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n). GHC isn't sure which one to pick!
You can get around this by marking your instance FreeIO instance as OVERLAPPING:
instance {-# OVERLAPPING #-} Functor f => MyMonadIO (FreeIO f) where
myLiftIO :: IO a -> FreeIO f a
myLiftIO m = FreeIO (Left <$> m)
However, this is a treacherous route to go down. You can find out more about why overlapping can be bad from the GHC user guide.
This FreeIO example was created by Edward Kmett. You can find another clever example of an overlapping instance in this reddit post.
If you are planning on writing a monad typeclass (like MyMonadIO) and
releasing it to Hackage, one option is to use the
DefaultSignatures
functionality. This makes it easier for users of your library to define
instances.
Using DefaultSignatures, defining the MyMonadIO class would look like this:
class Monad m => MyMonadIO m where
myLiftIO :: IO a -> m a
default myLiftIO
:: forall t n a.
( MyMonadIO n
, MonadTrans t
, m ~ t n
)
=> IO a -> t n a
myLiftIO = (lift :: n a -> t n a) . (myLiftIO :: IO a -> n a)
This says that there is a default implementation of myLiftIO for any t n,
where n is an instance of MyMonadIO, and t is an instance of
MonadTrans.
With this default siguature for myLiftIO, defining instances of MyMonadIO for ReaderT and StateT would look like this:
instance MyMonadIO m => MyMonadIO (ReaderT r m)
instance MyMonadIO m => MyMonadIO (StateT s m)
Very simple. You don't need to provide the function body of myLiftIO since
it will use the default.
The only drawback of this is that it is not widely done. The
DefaultSignatures machinery seems to be mainly used for generic
programming, not monad typeclasses.
Is it possible to implement a MonadTransControl instance for FreeT? I started with the following, but got stuck:
instance (Functor f) => MonadTransControl (FreeT f) where
newtype StT (FreeT f) r = FreeTStT r
liftWith unlift = lift $ unlift $ error "Stuck here"
restoreT inner = do
FreeTStT r <- lift inner
return r
If it is unimplementable, than why and is it possible to extend a specific free functor implementation somehow to make it implementable?
Disclaimer: turns out you need Traversable f constraint for MonadTransControl instance.
Warning: the instance in this answer does not obey all the laws of MonadTransControl
Pragmas and imports
{-# LANGUAGE TypeFamilies #-}
import qualified Data.Traversable as T
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Control
import Control.Monad.Trans.Free
import qualified Control.Monad.Free as F
Free monadic state
As I said in comments, the proper "monadic state" of FreeT f should be Free f (the one from Control.Monad.Free):
instance T.Traversable f => MonadTransControl (FreeT f) where
newtype StT (FreeT f) a = StTFreeT { getStTFreeT :: F.Free f a }
Now the implementation of restoreT changes a bit:
restoreT inner = do
StTFreeT m <- lift inner
F.toFreeT m
liftWith implementation
Before we look at the implementation let's see what should the type of liftWith be:
liftWith :: Monad m => (Run (FreeT f) -> m a) -> FreeT f m a
And Run (FreeT f) is actually
forall n b. Monad n => FreeT f n b -> n (StTFreeT f b)
So the implementation would be like that:
liftWith unlift = lift $ unlift (liftM StTFreeT . pushFreeT)
The rest is simple:
pushFreeT :: (T.Traversable f, Monad m) => FreeT f m a -> m (F.Free f a)
pushFreeT m = do
f <- runFreeT m
case f of
Pure x -> return (return x)
Free y -> liftM wrap $ T.mapM pushFreeT y
Why Traversable?
As you can see the problem is with pushFreeT function: it uses T.mapM (which is traverse but with Monad constraint). Why do we need it there? If you look at the definition of FreeT you may notice that (NB: this is rough, I forget about Pure here):
FreeT f m a ~ m (f (m (f ... )))
And as a result of pushFreeT we need m (Free f a):
m (Free f a) ~ m (f (f (f ... )))
So we need to "push" all fs to the end and join all ms in the head. Thus we need an operation that lets us push a single f through single m and this is exactly what T.mapM pushFreeT gives us:
mapM :: (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b)
mapM pushFreeT :: Traversable t => t (FreeT t m a) -> m (t (Free t a))
The laws
Every class instance usually come with laws. MonadTransControl is not an exception, so let's check if they hold for this instance:
liftWith . const . return = return
liftWith (const (m >>= f)) = liftWith (const m) >>= liftWith . const . f
These two laws obviously follow from laws for MonadTrans and the definition of liftWith.
liftWith (\run -> run t) >>= restoreT . return = t
Apparently, this law does not hold. This is because monad layers in t are collapsed when we pushFreeT. So the implemented liftWith merges effects in all layers of FreeT f m leaving us with the equivalent of m (Free f).
I'm currently working on Data.Fresh and Control.Monad.Trans.Fresh, which resp. define an interface for generating fresh variables, and a monad transformer which implements this interface.
I initially thought it would be possible to implement the Applicative instance for my FreshT v m with the only requirement that Applicative m exists. However, I got stuck and it seemed like I need to require Monad m. Not trusting my Haskell-fu, I then turned to the transformers package, and was surprised by what I found in Control.Monad.Trans.State.Lazy and .Strict:
instance (Functor m, Monad m) => Applicative (StateT s m) where
pure = return
(<*>) = ap
So here is my question: is it possible to create an instance with equivalent semantics with the following instance head?
instance (Applicative m) => Applicative (StateT s m) where
Consider that you have two functions:
f :: s -> m (s, a -> b)
g :: s -> m (s, a)
And you want to create a function h = StateT f <*> StateF g
h :: s -> m (s, b)
From the above you have an s you can pass to f so you have:
f' :: m (s, a -> b)
g :: s -> m (s, a)
However to get s out of f' you need the Monad (whatever you'd do with applicative it would still be in form of m s so you would not be able to apply the value to g).
You can play with the definitions and use free monad but for the collapse of state you need join.
Weaker variant of an Applicative transformer
Although it isn't possible to define an applicative transformer for StateT, It's possible to define a weaker variant that works. Instead of having s -> m (a, s), where the state decides the next effect (therefore m must be a monad), we can use m (s -> (a, s)), or equivalently m (State s a).
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Control.Monad.Trans
newtype StateTA s m a = StateTA (m (State s a))
This is strictly weaker than StateT. Every StateTA can be made into StateT (but not vice versa):
toStateTA :: Applicative m => StateTA s m a -> StateT s m a
toStateTA (StateTA k) = StateT $ \s -> flip runState s <$> k
Defining Functor and Applicative is just the matter of lifting operations of State into the underlying m:
instance (Functor m) => Functor (StateTA s m) where
fmap f (StateTA k) = StateTA $ liftM f <$> k
instance (Applicative m) => Applicative (StateTA s m) where
pure = StateTA . pure . return
(StateTA f) <*> (StateTA k) = StateTA $ ap <$> f <*> k
And we can define an applicative variant of lift:
lift :: (Applicative m) => m a -> StateTA s m a
lift = StateTA . fmap return
Update: Actually the above isn't necessary, as the composition of two applicative functors is always an applicative functor (unlike monads). Our StateTA is isomorphic to Compose m (State s), which is automatically Applicative:
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
Therefore we could write just
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Applicative
import Control.Monad.State
import Data.Functor.Compose
newtype StateTA s m a = StateTA (Compose m (State s) a)
deriving (Functor, Applicative)
Although, as noted in the previous answer, this instance cannot be defined in general, it is worth noting that, when f is Applicative and s is a Monoid, StateT s f is also Applicative, since it can be regarded as a composition of applicative functors:
StateT s f = Reader s `Compose` f `Compose` Writer s
One irritation with lazy IO caught to my attention recently
import System.IO
import Control.Applicative
main = withFile "test.txt" ReadMode getLines >>= mapM_ putStrLn
where getLines h = lines <$> hGetContents h
Due to lazy IO, the above program prints nothing. So I imagined this could be solved with a strict version of fmap. And indeed, I did come up with just such a combinator:
forceM :: Monad m => m a -> m a
forceM m = do v <- m; return $! v
(<$!>) :: Monad m => (a -> b) -> m a -> m b
f <$!> m = liftM f (forceM m)
Replacing <$> with <$!> does indeed alleviate the problem. However, I am not satisfied. <$!> has a Monad constraint, which feels too tight; it's companion <$> requires only Functor.
Is there a way to write <$!> without the Monad constraint? If so, how? If not, why not? I've tried throwing strictness all over the place, to no avail (following code does not work as desired):
forceF :: Functor f => f a -> f a
forceF m = fmap (\x -> seq x x) $! m
(<$!>) :: Functor f => (a -> b) -> f a -> f b
f <$!> m = fmap (f $!) $! (forceF $! m)
I don't think it's possible, and also the monadic forceM doesn't work for all monads:
module Force where
import Control.Monad.State.Lazy
forceM :: Monad m => m a -> m a
forceM m = do v <- m; return $! v
(<$!>) :: Monad m => (a -> b) -> m a -> m b
f <$!> m = liftM f (forceM m)
test :: Int
test = evalState (const 1 <$!> undefined) True
And the evaluation:
Prelude Force> test
1
forceM needs a strict enough (>>=) to actually force the result of its argument. Functor doesn't even have a (>>=). I don't see how one could write an effective forceF. (That doesn't prove it's impossible, of course.)