在State Monad中构造关于错误处理的最小Haskell示例 [英] Constructing minimal Haskell example on error-handling in the State Monad

查看:89
本文介绍了在State Monad中构造关于错误处理的最小Haskell示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在绞尽脑汁,试图了解如何将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...

我玩过StateTMaybeT,但无法使它们正常工作.我看过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:如果有人能展示如何使用StateTMaybeT(两个示例)来编写这段(非常琐碎的)代码,我将不胜感激. (我假设如果不使用转换器就无法编写此代码-是吗?)

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆