Haskell 失败时如何保存信息?

Haskell 失败时如何保存信息?,haskell,monads,monad-transformers,state-monad,Haskell,Monads,Monad Transformers,State Monad,我正在编写一些代码,使用StateTmonad转换器跟踪一些有状态信息(日志记录等) 我要传递给StateT的monad非常简单: data CheckerError a = Bad {errorMessage :: Log} | Good a deriving (Eq, Show) instance Monad CheckerError where return x = Good x fail msg = Bad msg (Bad msg) >&g

我正在编写一些代码,使用
StateT
monad转换器跟踪一些有状态信息(日志记录等)

我要传递给StateT的monad非常简单:

data CheckerError a = Bad {errorMessage :: Log} | Good a
    deriving (Eq, Show)


instance Monad CheckerError where
    return x = Good x

    fail msg = Bad msg

    (Bad msg) >>= f = Bad msg
    (Good x) >>= f = f x

type CheckerMonad a = StateT CheckerState CheckerError a
它只是一个
变体

让我烦恼的是
fail
的定义。在我的计算中,我在这个单子中产生了很多信息,即使失败了,我也希望保留这些信息。 目前,我唯一能做的就是将所有内容转换为
字符串
,并使用
字符串
作为参数传递给
失败
创建一个
实例

我想做的是:

fail msg = do
    info <- getInfoOutOfTheComputation
    return $ Bad info
fail msg=do

信息您的
检查错误
单子与
单子非常相似。我将在回答中使用
单子(及其对应的单子转换器)

单子变换器有一个微妙之处:顺序很重要。“内部”单子的效果优先于“外部”层的效果。考虑这两个可供选择的定义:<代码> CukMunad < /C> >:

import Control.Monad.State
import Control.Monad.Error

type CheckerState = Int     -- dummy definitions for convenience
type CheckerError = String

type CheckerMonad a = StateT CheckerState (Either String) a

type CheckerMonad' a = ErrorT String (State CheckerState) a
CheckerMonad
中,
是内部单子,这意味着故障将擦除整个状态。请注意此运行函数的类型:

runCM :: CheckerMonad a -> CheckerState -> Either CheckerError (a,CheckerState)
runCM m s = runStateT m s
您要么失败,要么返回一个结果以及到该点为止的状态

CheckerMonad'
中,
状态是内部单子。这意味着即使在发生故障的情况下,状态也将保持不变:

runCM' :: CheckerMonad' a -> CheckerState -> (Either CheckerError a,CheckerState)
runCM' m s = runState (runErrorT m) s
返回一对,其中包含到该点的状态以及失败或结果

这需要一点实践来培养如何正确订购单声道变压器的直觉。本节中的图表是一个很好的起点

另外,最好避免直接使用,因为它被认为是语言中的一个小缺点。相反,使用由错误转换器提供的用于抛出错误的专用函数。使用的
error
或其他实例时,请使用

sillycomp::CheckerMonad'Bool
sillycomp=do
修改(+1)
s runCM’sillycomp 2
加载包变压器-0.3.0.0。。。链接。。。完成。
加载包mtl-2.1.2。。。链接。。。完成。
(左“boo”,3)
*Main>runCM’sillycomp 3
(正确,正确,4)
error
有时使用起来很烦人,因为与
不同,它需要对错误类型进行约束。
Error
typeclass强制您定义两个错误构造函数
noMsg
strMsg
,这对您的类型可能有意义,也可能没有意义


您可以改为使用包中的,它允许您使用任何类型作为错误。使用时,使用
left
函数抛出错误。

简短回答:这不是
fail
的目的,所以它当然不起作用。@Carl然后告诉我应该如何实现这一点。我想要的是:1)一种在发生不好的事情时“停止”计算的方法2)保留在该点之前生成的有状态信息。我看到的所有能够实现1的示例都使用
fail
,而无法实现2。目前我唯一想到的是:
prettyFail=do state
fail
只是作为一种权宜之计来支持do表示法中的模式匹配失败。
sillycomp :: CheckerMonad' Bool
sillycomp = do
    modify (+1)
    s <- get 
    if s == 3
        then throwError "boo"
        else return True

*Main> runCM' sillycomp 2
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.2 ... linking ... done.
(Left "boo",3)

*Main> runCM' sillycomp 3
(Right True,4)