ice*_*man 4 monads haskell state-monad monad-transformers maybe
我正在扭曲我的大脑,试图理解如何将Statemonad与... 结合起来Maybe.
让我们从一个具体(并且故意琐碎/不必要)的例子开始,我们使用Statemonad来查找数字列表的总和:
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
Run Code Online (Sandbox Code Playgroud)
凉.
现在让我们修改它,以便Nothing在列表包含数字时返回a 0.换句话说,evalState addState' list应该返回Nothing(因为list包含a 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'
Run Code Online (Sandbox Code Playgroud)
......它有效,但我认为有更好的方法来做到这一点......
我玩过StateT,MaybeT而且我无法让他们工作.我看过Monad变形金刚的几个介绍,但他们要么没有触及这个特定的组合(即State + Maybe),要么这些例子太复杂了我无法理解.
TL; DR:如果有人能够展示如何使用StateT和MaybeT(两个例子)来编写这个(通常是微不足道的)代码片段,我将不胜感激.(我假设不使用变换器就无法编写此代码 - 这是不正确的?)
PS我的理解是,这StateT可能更适合这个例子,但从概念上看,这两个例子都有帮助,如果不是太麻烦的话.
更新:正如@Brenton Alker所指出的,我上面代码的第一个版本不起作用,因为简单的拼写错误(我错过了撇号).为了将问题集中在StateT/ 的使用上MaybeT,我正在纠正上面的帖子.只是想包括这个注释,以便为他的帖子提供背景信息.
我建议使用的类型是:
StateT [Int] Maybe Int
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
请注意,我以这样的方式写道,我没有使用任何Maybe特定的操作.实际上,如果你让编译器推断出类型签名,它将推断出这种更通用的类型:
addState' :: MonadPlus m => StateT [Int] m Int
Run Code Online (Sandbox Code Playgroud)
这有效,因为StateT有以下MonadPlus实例:
instance MonadPlus m => MonadPlus (StateT s m) where ...
Run Code Online (Sandbox Code Playgroud)
而Maybe将类型检查作为一个实例MonadPlus,这就是为什么当我们专注在上面的代码工作m来Maybe.