创建一个Reader和Maybe Monad的组合(Applicative Functor)

Dan*_*Man 6 monads haskell monad-transformers

我想做的是从Reader monad中制作一个Applicative Functor,它做了这样的事情:

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]
Run Code Online (Sandbox Code Playgroud)

但是,如果运行类似的东西

runReader myDataFromApplicative [1]
Run Code Online (Sandbox Code Playgroud)

而不是给我 MyData 0 0

我希望它能给我 Error

我正在玩创建自己的Reader Monad来实现这一目标,但无法弄明白.

我想象的是这样的事情(显然这只是一个大纲

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]
Run Code Online (Sandbox Code Playgroud)

哪个会输出

Success MyData 3 3
Error
Run Code Online (Sandbox Code Playgroud)

sha*_*ang 8

你不需要编写自己的monad,因为这正是monad变换器和monad堆栈解决的问题.由于你想要一个Reader和的组合Maybe,你可以使用ReaderT变换器和Maybemonad.例如

get2Sum :: ReaderT [Int] Maybe Int
get2Sum = do
    myData <- ask
    let fst2 = take 2 myData
    case length fst2 of
        2 -> return $ sum fst2
        _ -> lift Nothing
Run Code Online (Sandbox Code Playgroud)

get2Sum我们拥有Reader [Int]包含内部monad 的外部monad 的均值类型Maybe.在执行中get2Sum,lift用于在内部monad中运行操作(在这种情况下,只是信令错误Nothing).现在当你跑步时(注意T in runReaderT)

main = do
    print $ runReaderT myDataFromApplicative [1,2]
    print $ runReaderT myDataFromApplicative [1]
Run Code Online (Sandbox Code Playgroud)

你得到

Just (MyData 3 3)
Nothing
Run Code Online (Sandbox Code Playgroud)

您还可以在自定义内隐藏monad堆栈 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]
Run Code Online (Sandbox Code Playgroud)