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