在State Monad中构造关于错误处理的最小Haskell示例 [英] Constructing minimal Haskell example on error-handling in the State Monad
问题描述
我正在绞尽脑汁,试图了解如何将State
单子与Maybe
结合在一起.
I'm twisting my brain into knots trying to understand how to combine the State
monad with Maybe
.
让我们从一个具体的(故意是琐碎的/不必要的)示例开始,在该示例中,我们使用State
monad查找数字列表的总和:
Let's start with a concrete (and intentionally trivial/unnecessary) example in which we use a State
monad to find the sum of a list of numbers:
import Control.Monad.State
list :: [Int]
list = [1,4,5,6,7,0,3,2,1]
adder :: Int
adder = evalState addState list
addState :: State [Int] Int
addState = do
ms <- get
case ms of
[] -> return 0
(x:xs) -> put xs >> fmap (+x) addState
很酷.
现在让我们对其进行修改,以便在列表中包含数字0
时返回Nothing
.换句话说,evalState addState' list
应该返回Nothing
(因为list
包含0
).我以为可能看起来像这样...
Now let's modify it so that it returns a Nothing
if the list contains the number 0
. In other words, evalState addState' list
should return Nothing
(since list
contains a 0
). I thought it might look something like this...
addState' :: State [Int] (Maybe Int)
addState' = do
ms <- get
case ms of
[] -> return (Just 0)
(0:xs) -> return Nothing
(x:xs) -> put xs >> fmap (fmap (+x)) addState'
...它可以工作,但是我认为有更好的方法可以做到这一点...
...it works but I assume there's a better way to do this...
我玩过StateT
和MaybeT
,但无法使它们正常工作.我看过Monad变形金刚的一些介绍,但他们要么没有涉及这个特定的组合(即State + Maybe),要么示例太复杂了以至于我无法理解.
I've played around with StateT
and MaybeT
and I can't get them to work. I've looked at a couple of intros to Monad transformers but they either didn't touch on this particular combo (i.e., State + Maybe) or the examples were too complex for me to understand.
TL; DR:如果有人能展示如何使用StateT
和MaybeT
(两个示例)来编写这段(非常琐碎的)代码,我将不胜感激. (我假设如果不使用转换器就无法编写此代码-是吗?)
TL;DR: I'd appreciate if someone could show how to write this (admittedly trivial) piece of code using StateT
and MaybeT
(two examples). (I'm assuming it isn't possible to write this code without the use of transformers - is that incorrect?)
P.S.我的理解是,StateT
可能更适合此示例,但是从概念上看这两个示例也很有帮助.
P.S. My understanding is that StateT
is probably better suited for this example, but it would be helpful conceptually to see both examples, if not too much trouble.
更新:正如@Brenton Alker指出的那样,我上面的代码的第一个版本由于简单的错字(我错过了撇号)而无法正常工作.为了将问题集中在StateT
/MaybeT
的使用上,我正在更正上面的帖子.只是想包括这条笔记,以便为他的帖子提供背景信息.
Update: As pointed out by @Brenton Alker, my first version of the code above doesn't work because of simple typo (I was missing an apostrophe). In the interest of focusing the question on the use of StateT
/MaybeT
, I'm correcting the post above. Just wanted to include this note to give context to his post.
推荐答案
我建议使用的类型是:
StateT [Int] Maybe Int
使用Maybe
/MaybeT
的一种非常简单的方法是,每当您要失败时就调用mzero
,每当您要从失败的计算中恢复时都调用mplus
.即使它们位于其他monad转换器中也可以使用.
A really simple way to use Maybe
/MaybeT
is to just call mzero
whenever you want to fail and mplus
whenever you want to recover from a failed computation. This works even if they are layered within other monad transformers.
这是一个例子:
addState' :: StateT [Int] Maybe Int
addState' = do
ms <- get
case ms of
[] -> return 0
(0:xs) -> mzero
(x:xs) -> put xs >> fmap (fmap (+x)) addState
-- This requires generalizing the type of `addState` to:
addState :: Monad m => StateT [Int] m Int
请注意,我以这样的方式编写该代码,使得我没有使用任何Maybe
特定的操作.实际上,如果让编译器推断类型签名,它将推断出这种更通用的类型:
Notice that I wrote that in such a way that I didn't use any Maybe
-specific operations. In fact, if you let the compiler infer the type signature it will deduce this more general type instead:
addState' :: MonadPlus m => StateT [Int] m Int
之所以可行,是因为StateT
具有以下MonadPlus
实例:
This works because StateT
has the following MonadPlus
instance:
instance MonadPlus m => MonadPlus (StateT s m) where ...
然后Maybe
将作为MonadPlus
的实例进行类型检查,这就是为什么当我们将m
专门化为Maybe
时,上面的代码起作用的原因.
And Maybe
will type-check as an instance of MonadPlus
, which is why the above code works when we specialize m
to Maybe
.
这篇关于在State Monad中构造关于错误处理的最小Haskell示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!