问题 调试haskell:在每次调用时显示函数的名称


是否有一个工具可以自动“标记”某些功能,以便我可以获得“调用堆栈”的近似值。

实际上,我希望有一种类似于你写作的行为 fct = Debug.trace "fct" $ ... 无需在每个功能之前添加它。

我知道分析与-fprof-auto类似,但我需要在应用程序运行时显示它。

有一段时间,我有无限循环,这个显示可以立即显示哪些功能有问题。使用hlist和breakpoints并不是很有用,因为您必须知道循环中某个函数的名称。


4602
2017-09-03 15:38


起源

你知道“概率调试”技术吗?您开始运行程序,并且在您选择的任何时候,都可以进入调试器。您现在可能处于花费最多时间计算的函数中(因为您在任何给定函数中停止的概率与该函数花费的时间有关!)。 - Daniel Wagner
是的,这就是GHCi调试器文档所推荐的(你应该先设置-fbreak-on-exception)。但据我记得,它在我最后一次使用时效果不佳,而且在每次调用函数名称之前我都必须添加它来弄清楚发生了什么。 - Jeremy Cochoy


答案:


这是令人难以置信的丑陋;-),它只给你行号而不是函数名,但我很惊讶地发现它有效,所以我想我会分享它。它仍然比没有好。您可以使用C预处理器,就像在旧C天中一样:

{-# LANGUAGE CPP #-}

#define traceLoc trace (__FILE__ ++":"++ show __LINE__)

import Debug.Trace

f 0 = traceLoc $ 1
f n = traceLoc $ g (n-1)
g 0 = traceLoc $ 2
g n = traceLoc $ 2 * f (n-1)    

现在,

*Main> f 3
Test.hs:16
Test.hs:18
Test.hs:16
Test.hs:17
4

12
2017-09-03 16:07



什么样的CPP是这样的: __FILE__ ++":"++ show __LINE__ ;-)但它太酷了! - Sassa NF
@SassaNF这是带有文件名和行号的CPP宏的haskell。 CPP只是一个宏系统,没有理由要求宏产生任何特定的语言。 - Thomas M. DuBuisson
它更漂亮,虽然如果你有数百个功能,它仍然是一个痛苦:( - Jeremy Cochoy
只是好奇:如果你正在使用 Debug.Trace 无论如何,为什么不使用它 trace 功能?似乎正是@Jeremy所需要的。 - fjarri