6

我想做的是从 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
4

1 回答 1

8

您不需要编写自己的 monad,因为这正是 monad 转换器和 monad 堆栈解决的问题。由于您想要 aReader和的组合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

类型get2Sum意味着我们拥有Reader [Int]包含内部 monad 的外部 monad Maybe。在 的实现中get2Sumlift用于在内部 monad 中运行操作(在这种情况下,简单地用 表示错误Nothing)。现在当你运行时(注意T in runReaderT

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

你得到

Just (MyData 3 3)
Nothing

您还可以将 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]
于 2012-10-23T18:08:43.120 回答