Creating a combination of reader and possibly monad (applicative functor)

What I would like to do is make an applicative Functor from the Reader monad, which 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 you run something like

 runReader myDataFromApplicative [1] 

Instead of giving me MyData 0 0

I want him to give me Error

I played with creating my own Reader Monad to achieve this, but couldn't figure it out.

I think this is something like this (obviously this is just a circuit

 data SuccessReader ra = 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 outputs

 Success MyData 3 3 Error 
+6
source share
1 answer

You do not need to write your own monad, since this is exactly the problem that monad transformers and monads solve. Since you need a combination of Reader and Maybe , you can use a ReaderT transformer with the Maybe monad. For instance.

 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 get2Sum means that we have the external monad Reader [Int] , which contains the internal monad Maybe . In the get2Sum implementation, lift used to perform operations in the internal monad (in this case, just a signaling error with Nothing ). Now that you run (pay attention to T in runReaderT )

 main = do print $ runReaderT myDataFromApplicative [1,2] print $ runReaderT myDataFromApplicative [1] 

You are getting

 Just (MyData 3 3) Nothing 

You can also hide the monad stack inside 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] 
+8
source

All Articles