我怎样才能编写一个执行错误处理的状态monad?

Has*_*oob 8 monads state haskell state-monad monad-transformers

我需要编写一个也可以支持错误处理的状态monad.我正在考虑将Either monad用于此目的,因为它还可以提供有关导致错误的原因的详细信息.我发现使用也许单子的状态单子的定义,但我无法修改为使用,而不是可能.这是代码:

newtype StateMonad a = StateMonad (State -> Maybe (a, State))

instance Monad StateMonad where
(StateMonad p) >>= k = StateMonad (\s0 -> case p s0 of 
                                 Just (val, s1) -> let (StateMonad q) = k val in q s1
                                 Nothing -> Nothing)
return a = StateMonad (\s -> Just (a,s))

data State = State
{ log  :: String
, a    :: Int}
Run Code Online (Sandbox Code Playgroud)

Tho*_*son 11

考虑使用ExceptTfrom Control.Monad.Trans.Except(而不是使用Either).

import Control.Monad.State
import Control.Monad.Trans.Except
import Control.Monad.Identity

data MyState = S

type MyMonadT e m a = StateT MyState (ExceptT e m) a

runMyMonadT :: (Monad m) => MyMonadT e m a -> MyState -> m (Either e a)
runMyMonadT m = runExceptT . evalStateT m

type MyMonad e a = MyMonadT e Identity a
runMyMonad m = runIdentity . runMyMonadT m
Run Code Online (Sandbox Code Playgroud)

如果你不舒服的单子和单子变压器然后我会做第一!他们是一个巨大的帮助和程序员生产力表现的胜利.


Mic*_*man 7

有两种可能的解决方案.最接近您上面提供的代码的是:

newtype StateMonad e a = StateMonad (State -> Either e (a, State))

instance Monad (StateMonad e) where
    (StateMonad p) >>= k =
        StateMonad $ \s0 ->
            case p s0 of
                Right (val, s1) ->
                    let (StateMonad q) = k val
                     in q s1
                Left e -> Left e
    return a = StateMonad $ \s -> Right (a, s)

data State = State
    { log  :: String
    , a    :: Int
    }
Run Code Online (Sandbox Code Playgroud)

另一种形式在状态处理中移动错误处理:

newtype StateMonad e a = StateMonad (State -> (Either e a, State))

instance Monad (StateMonad e) where
    (StateMonad p) >>= k =
        StateMonad $ \s0 ->
            case p s0 of
                (Right val, s1) ->
                    let (StateMonad q) = k val
                     in q s1
                (Left e, s1) -> (Left e, s1)
    return a = StateMonad $ \s -> (Right a, s)

data State = State
    { log  :: String
    , a    :: Int
    }
Run Code Online (Sandbox Code Playgroud)

  • 另请注意,这两个在操作上有点不同.第二个版本允许可恢复错误,而第一个版本终止于第一个错误.如果您正在建模日志记录,请注意第一个版本也"丢失"登录错误. (4认同)