What I would like to do is make an Applicative Functor out of the Reader monad that does something like this:
data MyData = Int Int
get2Sum :: Reader [Int] Int
get2Sum = do
myData <- ask
let fst2 = take 2 myData
case length fst2 of
2 -> return $ sum fst2
_ -> return 0
myDataFromApplicative = MyData <$> get2Sum <*> get2Sum
main = print $ runReader myDataFromApplicative [1,2]
However, if run something like
runReader myDataFromApplicative [1]
Instead of giving me MyData 0 0
I want it to give me Error
I was playing around with creating my own Reader Monad to accomplish this, but couldn't quite figure it out.
What I imagine is something like this (obviously this is just an outline
data SuccessReader r a = Interm {runSuccessReader :: r -> SuccessReader a} | Success a | Error
throwError :: SuccessReader ()
get2Sum :: Reader [Int] Int
get2Sum = do
myData <- ask
let fst2 = take 2 myData
case length fst2 of
2 -> return $ sum fst2
_ -> throwError
myDataFromApplicative = MyData <$> get2Sum <*> get2Sum
main = do
print $ runSuccessReader myDataFromApplicative [1,2]
print $ runSuccessReader myDataFromApplicative [1]
which would output
Success MyData 3 3
Error
You don't need to write your own monad, as this is exactly the problem that monad transformers and monad stacks solve. Since you want a combination of a Reader
and Maybe
, you can use the ReaderT
transformer with the Maybe
monad. Eg
get2Sum :: ReaderT [Int] Maybe Int
get2Sum = do
myData <- ask
let fst2 = take 2 myData
case length fst2 of
2 -> return $ sum fst2
_ -> lift Nothing
The type of get2Sum
means that we have the outer monad Reader [Int]
which contains the inner monad Maybe
. In the implementation of get2Sum
, lift
is used to run operations in the inner monad (in this case, simply signalling error with Nothing
). Now when you run (note the T in runReaderT
)
main = do
print $ runReaderT myDataFromApplicative [1,2]
print $ runReaderT myDataFromApplicative [1]
you get
Just (MyData 3 3)
Nothing
You could also hide the monad stack inside a custom newtype
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Applicative
import Control.Monad.Reader
data MyData = MyData Int Int deriving Show
newtype MyMonad a = MyMonad (ReaderT [Int] Maybe a)
deriving (Functor, Applicative, Monad, MonadReader [Int])
runMyMonad :: MyMonad a -> [Int] -> Maybe a
runMyMonad (MyMonad m) = runReaderT m
myError :: MyMonad a
myError = MyMonad $ lift Nothing
get2Sum :: MyMonad Int
get2Sum = do
myData <- ask
let fst2 = take 2 myData
case length fst2 of
2 -> return $ sum fst2
_ -> myError
myDataFromApplicative = MyData <$> get2Sum <*> get2Sum
main = do
print $ runMyMonad myDataFromApplicative [1,2]
print $ runMyMonad myDataFromApplicative [1]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.