简体   繁体   English

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

[英]Creating a Combination of a Reader and Maybe Monad (Applicative Functor)

What I would like to do is make an Applicative Functor out of the Reader monad that does something like this: 我想做的是从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]

However, if run something like 但是,如果运行类似的东西

runReader myDataFromApplicative [1]

Instead of giving me MyData 0 0 而不是给我MyData 0 0

I want it to give me Error 我希望它给我Error

I was playing around with creating my own Reader Monad to accomplish this, but couldn't quite figure it out. 我正在玩创建自己的Reader Monad来实现这一目标,但无法弄明白。

What I imagine is something like this (obviously this is just an outline 我想象的是这样的事情(显然这只是一个大纲

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]

which would output 哪个会输出

Success MyData 3 3
Error

You don't need to write your own monad, as this is exactly the problem that monad transformers and monad stacks solve. 你不需要编写自己的monad,因为这正是monad变换器和monad堆栈解决的问题。 Since you want a combination of a Reader and Maybe , you can use the ReaderT transformer with the Maybe monad. 由于您需要ReaderMaybe的组合,因此您可以将ReaderT转换器与Maybe monad一起使用。 Eg 例如

get2Sum :: ReaderT [Int] Maybe Int
get2Sum = do
    myData <- ask
    let fst2 = take 2 myData
    case length fst2 of
        2 -> return $ sum fst2
        _ -> lift Nothing

The type of get2Sum means that we have the outer monad Reader [Int] which contains the inner monad Maybe . get2Sum的类型意味着我们有外部monad Reader [Int] ,它包含内部monad Maybe In the implementation of get2Sum , lift is used to run operations in the inner monad (in this case, simply signalling error with Nothing ). get2Sum的实现中, lift用于在内部monad中运行操作(在这种情况下,简单地用Nothing发出错误信号)。 Now when you run (note the T in runReaderT ) 现在运行时(注意runReaderTT

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

you get 你得到

Just (MyData 3 3)
Nothing

You could also hide the monad stack inside a custom newtype 您也可以隐藏自定义里面的单子堆栈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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM