我想做的是在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]
但是,如果运行类似
的话runReader myDataFromApplicative [1]
而不是给我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]
将输出
Success MyData 3 3
Error
答案 0 :(得分:8)
你不需要编写自己的monad,因为这正是monad变换器和monad堆栈解决的问题。由于您需要Reader
和Maybe
的组合,因此可以将ReaderT
转换器与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
get2Sum
的类型意味着我们拥有包含内部monad Reader [Int]
的外部monad Maybe
。在get2Sum
的实现中,lift
用于在内部monad中运行操作(在这种情况下,只是用Nothing
发出错误信号)。现在当你跑步时(注意runReaderT
中的 T )
main = do
print $ runReaderT myDataFromApplicative [1,2]
print $ runReaderT myDataFromApplicative [1]
你得到了
Just (MyData 3 3)
Nothing
您还可以在自定义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]