Hello, I have seen it said that all Monads are Applicative Functors because you can just do:
instance (Monad f, Applicative f) => Applicative (ReaderT r f) where pure = return (<*>) = ap However, that instance for ReaderT does not exhibit the properties I was hoping for. By substitution the definition of ap: ap :: (Monad m) => m (a -> b) -> m a -> m b ap = liftM2 id liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) } we see that it becomes: instance (Monad f, Applicative f) => Applicative (ReaderT r f) where pure = return f <*> x = do { f' <- f; x' <- x; return (f' x') } What I would prefer is: instance (Monad f, Applicative f) => Applicative (ReaderT r f) where pure a = ReaderT $ const (pure a) f <*> a = ReaderT $ \r -> ((runReaderT f r) <*> (runReaderT a r)) I assume that only one version is correct, but I am having a hard time figuring out which one. I have attached a file which shows my motivation for prefering the second variation. There is a 'looker' function which does three lookups and combines the results using the Applicative Functor. With the first Applicative instance for ReaderT you will only get a failure message for the first lookup that fails -- which is what you expect with monadic behaviour. With the second instance, you get back a list of all the lookups that failed, which seems like what I would expect with Applicative Functor behaviour. Thanks! - jeremy
{-# LANGUAGE FlexibleContexts, FlexibleInstances #-} module Main where import Control.Applicative (Applicative((<*>), pure), (<$>)) import Control.Monad (Monad((>>=), return), ap) import Control.Monad.Reader (MonadReader(ask, local), ReaderT(ReaderT, runReaderT)) import Data.Monoid(Monoid(mappend)) instance (Monad f, Applicative f) => Applicative (ReaderT r f) where pure = return (<*>) = ap {- instance (Monad f, Applicative f) => Applicative (ReaderT r f) where pure a = ReaderT $ const (pure a) f <*> a = ReaderT $ \r -> ((runReaderT f r) <*> (runReaderT a r)) -} instance (Monoid e) => Applicative (Either e) where pure = Right (Left errF) <*> (Left errA) = Left (errF `mappend` errA) (Left err) <*> _ = Left err _ <*> (Left err) = Left err (Right f) <*> (Right a) = Right (f a) instance Monad (Either [String]) where return = Right (Right a) >>= f = f a (Left e) >>= f = (Left e) fail str = Left [str] lookupE :: (Eq a) => a -> [(a,b)] -> (Either a b) lookupE a env = case lookup a env of Just b -> Right b Nothing -> Left a look :: String -> ReaderT [(String,b)] (Either [String]) b look a = do env <- ask case lookup a env of Just b -> return b Nothing -> fail a looker :: ReaderT [(String, Int)] (Either [String]) (Int, Int, Int) looker = ((,,) <$> look "foo" <*> look "bar" <*> look "baz") test :: Either [String] (Int, Int, Int) test = runReaderT looker [("bar", 1)]
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe