首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在状态monad中使用Debug.Trace.trace?

如何在状态monad中使用Debug.Trace.trace?
EN

Stack Overflow用户
提问于 2012-08-07 20:22:08
回答 3查看 2.1K关注 0票数 9

我想跟踪state monad中的变化。这不起作用:

代码语言:javascript
复制
main :: IO ()
main = do
    print $ snd $ execState compute initialState

traceThis :: (Show a) => a -> a
traceThis x = trace ("test: " ++ show x) x

compute :: State ([Row], Integer) String
compute = liftM traceThis $ get >>= \(rs, result) -> put (rs, result + 3) >> return "foo"

不会打印任何内容(除了main函数中打印的最终结果,该结果已正确更新)。

有什么想法或替代方案来跟踪状态吗?我想用它来检查项目euler解决方案的正确性。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-07 20:49:23

在您的案例中,问题是traceThis永远不会被评估。Haskell是一种惰性语言,因此它只计算需要的表达式。由于您不评估计算结果,只评估状态,因此没有必要在compute中评估traceThis。例如,如果您打印

代码语言:javascript
复制
print $ evalState compute initialState

然后在调用traceThis时对有状态计算的结果值进行求值。

一个更好的选择是定义一个一元函数,每当对一元计算的任何部分求值时,该函数强制打印结果值:

代码语言:javascript
复制
traceState :: (Show a) => a -> State s a
traceState x = state (\s -> trace ("test: " ++ show x) (x, s))

compute :: State ([Int], Integer) String
compute = get >>= \(rs, result) -> put (rs, result + 3)
              >> return "foo"
              >>= traceState

更新:这可以推广到任意的monad。要点是,trace必须包装一元计算,而不仅仅是内部的值,以便在计算>>=时对其进行计算,而不管内部的值是否进行计算:

代码语言:javascript
复制
traceMonad :: (Show a, Monad m) => a -> m a
traceMonad x = trace ("test: " ++ show x) (return x)
票数 12
EN

Stack Overflow用户

发布于 2012-08-07 20:40:45

这里有一个替代方案。使用StateT s IO作为您的monad:

代码语言:javascript
复制
compute :: StateT ([Row], Integer) IO String
compute = do
    (rs, result) <- get
    lift $ putStrLn "result = " ++ show result
    put (rs, result + 3)
    return "foo"

现在,您可以使用lift在任何地方交错执行IO操作。

要了解有关monad transformers的更多信息,我建议您阅读优秀的介绍:Monad Transformers - Step by Step

票数 5
EN

Stack Overflow用户

发布于 2012-08-07 20:44:57

当您调用execState时,您只是请求最终的状态,而不是compute函数返回的值。另一方面,liftM将您的traceThis函数提升为State monad中的一个不涉及状态的操作。因此,由于惰性,只有在强制计算compute返回的值的情况下才会调用traceThis。通常,为了让trace正常工作,您必须确保调用它的值得到计算。

Debug.Trace通常只适用于快速调试-它不是一个功能非常强大的日志系统,并且由于懒惰而很难使用。如果您正在寻找一种更健壮的方法,您可以向状态元组添加另一个元素(可能是一个字符串列表),并让compute函数向其中写入日志消息。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11845863

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档