6

私がやりたいのは、次のようなことを行うReaderモナドからApplicativeFunctorを作成することです。

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

私はこれを達成するために独自のリーダーモナドを作成することで遊んでいましたが、それを完全に理解することはできませんでした。

私が想像するのはこのようなものです(明らかにこれは単なる概要です

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

これはまさにモナド変換子とモナドスタックが解決する問題であるため、独自のモナドを作成する必要はありません。Readeraと、の組み合わせが必要なため、モナドでトランスフォーマーをMaybe使用できます。例えばReaderTMaybe

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外側のモナドがあることを意味します。の実装では、は内部モナドで操作を実行するために使用されます(この場合、単にエラーを)で通知します。今実行すると(のTに注意してください)Reader [Int]Maybeget2SumliftNothingrunReaderT

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]
于 2012-10-23T18:08:43.120 に答える