如何强制调试跟踪语句按顺序求值?

时间:2018-12-01 13:18:31

标签: debugging haskell io lazy-evaluation trace

import Debug.Trace

main  :: IO ()
main = do
  let b = (fff 2 10)
  print b
  let c = (fff 3 10)
  print c
  print "---"


ff :: (->) Int Int
ff = do
  x <- traceShow "x is: " . traceShowId
  pure $ (x)

fff :: Int -> Int -> Int
fff = do
  (-) . ff

跟踪函数似乎是延迟计算的,或者意味着输出可能与以下内容有所不同

"x is: "
2
-8
"x is: "
-7
3
"---"

然后在另一次运行中:

"x is: "
2
"x is: "
3
-8
-7
"---"

我已经尝试了以下建议:How do I force evaluation of an IO action within `unsafePerformIO`?(BangPatterns实用注解+ $!),并添加了StrictStrictData实用注解,但是我仍然得到了行为不一致。

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE Strict #-}
{-# LANGUAGE StrictData #-}

import Debug.Trace

main  :: IO ()
main = do
  let !b = (fff 2 10)
  print b
  let !c = (fff 3 10)
  print c
  print "---"

ff :: (->) Int Int
ff = do
  x <- id $! (traceShow "x is: " . traceShowId)
  pure $ (x)

fff :: Int -> Int -> Int
fff = do
  (-) . ff

我也尝试使用unsafePerformIo,但这具有相似的行为:

hmm :: a -> a
hmm x = unsafePerformIO $! do
  pure x

ff :: Int -> Int
ff z = do
  hmm (trace "x is: " . traceShowId) $ z 

是否有解决方案,而不必了解严格性/ Haskell的评估?

3 个答案:

答案 0 :(得分:1)

Debug.Trace函数会打印到stderr,因此可以预期会发生交织。

至少,您可以将x和它前面的字符串放在一起,以区别于其他print输出。

ff :: Int -> Int
ff x = trace ("x is: " ++ show x) x

您还可以使用unsafePerformIO重新定义打印到stdout的跟踪功能,以强制执行某些排序。

答案 1 :(得分:1)

听起来您正在处理缓冲问题。您可以使用hFlush或仅设置缓冲:

hSetBuffering stderr NoBuffering
hSetBuffering stdout NoBuffering

答案 2 :(得分:1)

myTrace :: Show a => a -> a
myTrace x = unsafePerformIO $ do
  print x
  pure x

以上似乎效果很好。感谢https://stackoverflow.com/users/6863749/li-yao-xia