Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何在状态monad中使用Debug.Trace.Trace?_Haskell - Fatal编程技术网

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

Haskell 如何在状态monad中使用Debug.Trace.Trace?,haskell,Haskell,我想跟踪单子状态的变化。这不起作用: 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 &g

我想跟踪单子状态的变化。这不起作用:

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"
不会打印任何内容(除了主函数中已正确更新的打印的最终结果)


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

这里有一个替代方案。使用
StateT s IO
作为单子:

compute :: StateT ([Row], Integer) IO String
compute = do
    (rs, result) <- get
    lift $ putStrLn "result = " ++ show result
    put (rs, result + 3)
    return "foo"
compute::StateT([Row],Integer)IO字符串
计算=do

(rs,result)当您调用
execState
时,您只是请求最终状态,而不是请求
compute
函数返回的值<另一方面,code>liftM
会将
trace此
函数提升到
状态下的动作
单子,该单子不接触该状态。因此,由于惰性,
trace只有在您强制计算
compute
返回的值时才会调用此
。通常,要使
trace
正常工作,必须确保对调用它的值进行求值

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

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

打印$evalState计算初始状态
然后在调用
traceThis
的同时计算有状态计算的结果值

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

tracstate::(显示a)=>a->状态s a
traceState x=状态(\s->trace(“测试:++显示x)(x,s))
compute::State([Int],整数)字符串
compute=get>>=\(rs,result)->put(rs,result+3)
>>返回“foo”
>>=地产
更新:这可以推广到任意单子。要点是,
trace
必须包装一元计算,而不仅仅是内部的值,以便在计算
>=
时对其进行计算,而不管内部的值是否计算:

traceMonad::(显示a,单子m)=>a->m a
traceMonad x=跟踪(“测试:”++显示x)(返回x)

谢谢您的解释。我也想到了懒惰,但由于结果被打印出来,我放弃了这种可能性。。。我不确定我是否喜欢添加大量日志记录,因为出于性能原因,它将在将来被删除。这似乎是一个简单的解决方案,我唯一的罪魁祸首是使用monad transformer,因为我听说它们很慢,我在这里需要良好的性能。无论您是否意识到,您已经为monad transformer支付了费用<代码>状态s只是状态s标识的类型同义词。此外,大多数关于monad变压器性能的担忧被夸大了。我建议您自己对其进行基准测试,并与
Debug.Trace
的性能进行比较,然后再关闭它。非常好!一旦我不再需要日志记录,我可以通过删除一个表达式来关闭它。@somesoaccount用一个更通用的解决方案更新了答案。