Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Combination of a Reader and Maybe Monad (Applicative Functor)

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
like image 874
DantheMan Avatar asked Oct 23 '12 17:10

DantheMan


People also ask

What are Functors Applicatives and monads?

A functor is a data type that implements the Functor typeclass. An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.

Are all monads applicative functors?

Every Monad is an Applicative Just as IO , every monad can be made into an applicative functor.

What is an applicative in Haskell?

Definition. In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a.

Is maybe a functor Haskell?

Another simple example of a functor is the Maybe type. This object can contain a value of a particular type as Just , or it is Nothing (like a null value).


1 Answers

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. E.g.

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]
like image 172
shang Avatar answered Sep 29 '22 09:09

shang