2014-11-24 42 views
3

我正在将我的大脑扭成节,试图了解如何将State monad与Maybe合并。在State Monad上的错误处理中构建最小的Haskell示例

让我们先从一个具体的(和故意琐碎/不必要的)例子中,我们使用State单子找到数字列表的总和:

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 

酷。

现在让我们修改它,使其返回Nothing,如果列表包含数字0。换句话说,evalState addState' list应该返回Nothing(因为list包含0)。我想这可能是这个样子......

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' 

...它的工作原理,但我认为有一个更好的方式来做到这一点...

我已经StateTMaybeT和玩耍了我无法让他们工作。我已经看了一些对Monad变形金刚的介绍,但是他们或者没有涉及到这个特殊的组合(即State + Maybe),或者这些例子太复杂了,以至于我无法理解。

TL; DR:我会很感激,如果有人可以显示如何使用StateTMaybeT(两个例子)来写这个(当然微不足道)的代码。 (我假设在不使用变压器的情况下编写此代码是不可能的 - 是不正确的?)

P.S.我的理解是,StateT可能更适合这个例子,但从概念上讲,如果不是太麻烦,看两个例子都会有所帮助。

更新:正如@Brenton Alker指出的,由于简单的错字(我错过了一个撇号),我上面的第一个版本的代码不起作用。为了集中关注使用StateT/MaybeT的问题,我正在纠正上面的帖子。只是想包括这个笔记给他的职位的背景。

回答

8

我会建议使用的类型是:用

StateT [Int] Maybe Int 

一个非常简单的方法Maybe/MaybeT是只叫mzero只要你想失败,mplus每当你想从失败的计算中恢复。即使它们在其他monad变换器中分层也是有效的。

下面是一个例子:

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特异性操作的方式。事实上,如果你让编译器推断类型签名会推断,而不是更一般的类型:

addState' :: MonadPlus m => StateT [Int] m Int 

这工作,因为StateT具有以下MonadPlus实例:

instance MonadPlus m => MonadPlus (StateT s m) where ... 

而且Maybe将类型 - 请作为MonadPlus的实例进行检查,这就是为什么上述代码适用于我们专门致力于mMaybe

+0

你我们如何运行这个'StateT'函数?你的代码编译(假设我在原始文章中纠正了@Brenton Alker指出的撇号),但我无法使用以下(在GHCi中)运行它:'evalState addState'list'。有什么建议么? – iceman 2014-11-24 02:29:23

+2

@DipakC,'evalStateT' – luqui 2014-11-24 02:40:52

1

我相信你的解决方案基本上是正确的,你只是有一些小问题。

  1. 您递归调用addState缺少素数 - 即。它应该是addState'(我怀疑这只是粘贴问题的问题,鉴于报告的错误)
  2. 你断言adder :: Int,但在新的版本,它应该是adder :: Maybe Int - 我认为这是错误的类型你”重新获得。

不幸的是,我目前没有资源尝试变形金刚版本。

+0

是的,你的确是正确的:撇号... *红脸* – iceman 2014-11-24 02:30:09