GHC.Exts
个包导出breakpoint
and breakpointCond
。有谁知道如何使用这些功能?
从他们的名字我想他们会允许我设置永久GHCi断点,但是当我将它们添加到我的程序时没有任何反应。例如,当我将此程序加载到GHCi并使用main
,:main
或:trace main
运行时,不会触发任何断点:
import GHC.Exts
idNat x = breakpointCond (x > 0) x
main = do
putStrLn "Starting main"
putStrLn . show $ idNat 3
putStrLn $ breakpoint "Ending main"
注意:我知道如何使用:break
在GHCi中设置断点,而我正在使用GHC 7.6.3。
答案 0 :(得分:2)
查看提交历史记录,似乎是此功能used to work at some point。但是,显然它已被删除(无论是意外还是故意)when the implementation of breakpoints was reworked(grep for breakpointName
)。我filed a ticket about this。
答案 1 :(得分:1)
以下是一些解决方法的摘要,没有一个非常令人满意。
将此Breakpoint
模块放在源树中:
module Breakpoint where
breakpoint :: a -> a
breakpoint x = x
breakpointCond :: Bool -> a -> a
breakpointCond True x = x
breakpointCond False x = x
导入Breakpoint
而不是GHC.Exts
。 (我们只能在解释代码上设置断点,因此我们不能简单地在GHC.Exts
断点函数上设置断点。)
在GHCi中加载代码并在Breakpoint
模块中设置适当的断点:
ghci> :load <your main module>
ghci> :break Breakpoint 4
ghci> :break Breakpoint 7
请注意,第二个断点位于True
的{{1}}分支上。
跟踪您的代码:
breakpointCond
这种方法的问题在于你获得了一堆断点
在ghci> :trace main
模块中,但当您达到它们的实际值时
计算(你真正关心的)通常不在历史中
跟踪。我不明白为什么会这样,但这是一个例子
说明一下:
Breakpoint
然后:
module Eg2 where
import Breakpoint
fib 0 = 0
fib 1 = 1
fib n = breakpoint $ fib (n-1) + fib (n-2)
现在,请注意ghci> :load Eg2.hs
ghci> :break Breakpoint 4
,这样我们fib 3 = fib 2 + fib 1 = (fib 1 + fib 0) + fib 1
会导致我们点击两个断点,一次是fib 3
,一次是fib 3
。但是:
fib 2
所以,是的,我们在ghci> :trace fib 3
Stopped at Breakpoint.hs:4:5-20
_result :: a = _
[Breakpoint.hs:4:5-20] *Eg2
ghci> :history
-1 : fib (Eg2.hs:6:13-46)
-2 : fib (Eg2.hs:(4,5)-(6,46))
<end of history>
[Breakpoint.hs:4:5-20] *Eg2
ghci> :back
Logged breakpoint at Eg2.hs:6:13-46
_result :: a1
n :: Integer
[-1: Eg2.hs:6:13-46] *Eg2
ghci> n
3
达到了一个断点。但那时:
fib 3
只有[-1: Eg2.hs:6:13-46] *Eg2
ghci> :continue
Stopped at Breakpoint.hs:4:5-20
_result :: a = _
[Breakpoint.hs:4:5-20] *Eg2
ghci> :history
-1 : breakpoint (Breakpoint.hs:4:5-20)
-2 : fib (Eg2.hs:6:13-46)
-3 : fib (Eg2.hs:(4,5)-(6,46))
<end of history>
[Breakpoint.hs:4:5-20] *Eg2
ghci> :back
Logged breakpoint at Breakpoint.hs:4:5-20
_result :: a
[-1: Breakpoint.hs:4:5-20] *Eg2
ghci> :back
Logged breakpoint at Eg2.hs:6:13-46
_result :: a1
n :: Integer
[-2: Eg2.hs:6:13-46] *Eg2
ghci> n
3
在堆栈上?甚至没有fib 3
电话
虽然我们目前停在断点处!的确,继续
完成,返回fib 2
:
fib 3 = 2
使[-2: Eg2.hs:6:13-46] *Eg2
ghci> :continue
2
调用的上下文可用并不困难
在破发点。虽然这并没有解决问题
历史记录没有告诉你如何到达断点,它确实如此
让你以交互方式检查上下文(比“printf”更好
调试“与breakpoint
。”。
为断点函数添加上下文参数:
Debug.Trace
因为GHCi仅在您休息时停止显示自由变量 一点,你不能用更简单的定义,如
module Breakpoint2 where
breakpoint :: b -> a -> a
breakpoint y x =
const x y
breakpointCond :: Bool -> b -> a -> a
breakpointCond True y x =
const x y
breakpointCond False _ x = x
现在再考虑我们的例子,但这次我们手动传递
我们关心breakpoint y x = x
的背景:
breakpoint
我们不能检查module Eg3 where
import Breakpoint2
fib 0 = 0
fib 1 = 1
fib n = breakpoint ("n",n) $ fib (n-1) + fib (n-2)
:
n
第一次通话时见ghci> :load Eg3.hs
ghci> :break Breakpoint2 5
:
n = 3
第二次通话时见ghci> :trace fib 3
Stopped at Breakpoint2.hs:5:7-15
_result :: a = _
x :: a = _
y :: ([Char], Integer) = ("n",3)
[Breakpoint2.hs:5:7-15] *Eg3
ghci> :continue
:
n = 2
使用上下文进行交互式计算:
Stopped at Breakpoint2.hs:5:7-15
_result :: a = _
x :: a = _
y :: ([Char], Integer) = ("n",2)
然而,跟踪历史仍然相当无用,包括
[Breakpoint2.hs:5:7-15] *Eg3
ghci> let (_,n) = y
[Breakpoint2.hs:5:7-15] *Eg3
ghci> n * n
4
次来电,但会breakpoint
来电。{/ p>
fib
功能的目标是让您轻松设置
代码中的持久性断点,而不是使用一堆breakpoint
每次行号更改时变为无效的语句。但是,手动
设置断点确实会产生更好的历史记录。例如:
:break <some line> <your module>
直接设置断点:
module Eg4 where
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
我们需要列号(13)来在RHS上建立断点
ghci> :load Eg4.hs
ghci> :break Eg4 5 13
,而不是整个定义。现在我们得到了适当的痕迹:
fib
ghci> :trace fib 4
Stopped at Eg4.hs:5:13-33
_result :: a1 = _
n :: Integer = 4
[Eg4.hs:5:13-33] *Eg4
ghci> :continue
Stopped at Eg4.hs:5:13-33
_result :: a1 = _
n :: Integer = 3
[Eg4.hs:5:13-33] *Eg4
ghci> :continue
Stopped at Eg4.hs:5:13-33
_result :: a1 = _
n :: Integer = 2
[Eg4.hs:5:13-33] *Eg4
ghci> :continue
Stopped at Eg4.hs:5:13-33
_result :: a1 = _
n :: Integer = 2
[Eg4.hs:5:13-33] *Eg4
ghci> :back
Logged breakpoint at Eg4.hs:5:13-33
_result :: a1
n :: Integer
[-1: Eg4.hs:5:13-33] *Eg4
ghci> n
2
[-1: Eg4.hs:5:13-33] *Eg4
ghci> :back
Logged breakpoint at Eg4.hs:5:13-33
_result :: a1
n :: Integer
[-2: Eg4.hs:5:13-33] *Eg4
ghci> n
3
[-2: Eg4.hs:5:13-33] *Eg4
ghci> :back
Logged breakpoint at Eg4.hs:5:13-33
_result :: a1
n :: Integer
[-3: Eg4.hs:5:13-33] *Eg4
ghci> n
4
[-3: Eg4.hs:5:13-33] *Eg4
ghci> :history
-1 : fib (Eg4.hs:5:13-33)
-2 : fib (Eg4.hs:5:13-33)
-3 : fib (Eg4.hs:5:13-33)
-4 : fib (Eg4.hs:(3,5)-(5,33))
<end of history>
breakpointCond
似乎更有用,因为GHCi没有
条件断点,但这些可能会受到编辑你的影响
代码在断点条件下包含无意义的分支。对于
例如,假设我们只想在breakpointCond
为偶数时中断:
n
现在,在第6行,我们只停留在module Eg5 where
fib 0 = 0
fib 1 = 1
fib n = case even n of
True -> fib (n-1) + fib (n-2)
False -> fib (n-1) + fib (n-2)
。当然,这个
变换有点烦人,例如我们不能改为
n
从那以后fib n = case even n of
True -> r
False -> r
where r = fib (n-1) + fib (n-2)
中的n
不可用,我们不能使用“if”语句,
因为GHCi不会让你在其中设置一个断点。