我有一个简单的递归程序,并不是很有效。因此,我尝试使用ghci调试器来确定发生了什么。我在所有函数行recurse
,progress
和shaded
上设置了断点,它捕获了前几个函数。但当我到达progress
的第二行时,每次调用:继续让我回到同一行代码上,即使我正在调用recurse
和shaded
在那里,并期待我的断点工作。这是代码:
import System.Environment
type Pos = (Int,Int)
type Acc = ([[Pos]], [Pos])
main = do
getArgs >>= putStrLn . show . length . combos . read . head
combos n = recurse n [] (allPos n) []
recurse :: Int -> [[Pos]] -> [Pos] -> [Pos] -> [[Pos]]
recurse n done avail inProg
| length inProg == n = inProg:done
| null avail = done
| otherwise = fst $ foldr (progress n inProg) (done,avail) avail
progress :: Int -> [Pos] -> Pos -> Acc -> Acc
progress n inProg pos (done, avail) =
(recurse n done (filter (not . shaded pos) remain) (pos:inProg), remain)
where remain = tail avail
allPos n = [ (i,j) | i <- [0..n-1], j <- [0..n-1] ]
shaded :: Pos -> Pos -> Bool
shaded (i,j) (k,l) =
k == i
|| l == j
|| k+l == i+j
|| k-l == i-j
|| abs (k-i) < 3 && abs (l-j) < 3
为什么ghci调试器不会在progress
调用的函数中的断点处停止?是否有类似&#34;非重入&#34;把它们关掉?如何在每次递归调用这些函数时让调试器中断?
GHCi版本7.8.4
更新:我怀疑这可能与缓存结果有关,但对我来说这些功能已使用相同的参数调用两次并不明显。可能是我的代码中的错误?
答案 0 :(得分:4)
我认为它按预期工作,但你必须考虑延迟评估。
如果你在recurse
(第13 - 15行)的保护线和正在进行的递归调用(第19行)中断,当程序以{{1}运行时,你会看到这种模式}:
:main 2
但是,如果您更改Stopped at prog0.hs:13:6-23 - recurse
Stopped at prog0.hs:14:6-15 - recurse
Stopped at prog0.hs:15:18-67 - recurse, call to foldr progress
Stopped at prog0.hs:19:3-74 - in progress, pos = (1,1)
Stopped at prog0.hs:19:3-74 - in progress, pos = (1,0)
Stopped at prog0.hs:19:3-74 - in progress, pos = (0,1)
Stopped at prog0.hs:19:3-74 - in progress, pos = (0,0)
Stopped at prog0.hs:13:6-23 - in recurse
Stopped at prog0.hs:14:6-15
Stopped at prog0.hs:13:6-23 - in recurse
Stopped at prog0.hs:14:6-15
Stopped at prog0.hs:13:6-23 - in recurse
Stopped at prog0.hs:14:6-15
Stopped at prog0.hs:13:6-23 - in recurse
Stopped at prog0.hs:14:6-15
以强制其结果:
progress
然后断点模式是:
import Control.DeepSeq
progress n inProg pos (done, avail) = let
result = (recurse n done (filter (not . shaded pos) remain) (pos:inProg), remain)
in deepseq result result
where remain = tail avail
Stopped at prog1.hs:14:6-23 - recurse
Stopped at prog1.hs:15:6-15 - recurse
Stopped at prog1.hs:16:18-67 - recurse, call to foldr progress
Stopped at prog1.hs:21:6-26 - progress, pos = (1,1)
Stopped at prog1.hs:14:6-23 - recurse
Stopped at prog1.hs:15:6-15
Stopped at prog1.hs:21:6-26 - progress, pos = (1,0)
Stopped at prog1.hs:14:6-23 - recurse
Stopped at prog1.hs:15:6-15
Stopped at prog1.hs:21:6-26 - progress, pos = (0,1)
Stopped at prog1.hs:14:6-23 - recurse
Stopped at prog1.hs:15:6-15
Stopped at prog1.hs:21:6-26 - progress, pos = (0,0)
Stopped at prog1.hs:14:6-23 - recurse
Stopped at prog1.hs:15:6-15
的递归调用现在是交错的,因为我们正在立即强制它们。
答案 1 :(得分:3)
我正在添加另一个答案来演示如何使用Debug.Trace
使用纯函数执行“printf”调试。
以下是recurse
和progress
,其中添加了跟踪语句以供打印
他们的电话参数。我们可以安全地使用undefined
,因为
跟踪调用将始终返回False。
import System.Environment
import Debug.Trace
...
recurse :: Int -> [[Pos]] -> [Pos] -> [Pos] -> [[Pos]]
recurse n done avail inProg
| trace msg False = undefined
| length inProg == n = inProg:done
| null avail = done
| otherwise = fst $ foldr (progress n inProg) (done,avail) avail
where msg = unwords ["recurse:", show n, show done, show avail, show inProg]
progress :: Int -> [Pos] -> Pos -> Acc -> Acc
progress n inProg pos (done, avail)
| trace msg False = undefined
where msg = unwords ["progress:", show n, show inProg, show pos, show (done, avail)]
progress n inProg pos (done, avail) =
(recurse n done (filter (not . shaded pos) remain) (pos:inProg), remain)
where remain = tail avail
...
这是:main 2
的输出:
recurse: 2 [] [(0,0),(0,1),(1,0),(1,1)] []
progress: 2 [] (1,1) ([],[(0,0),(0,1),(1,0),(1,1)])
recurse: 2 [] [] [(1,1)]
progress: 2 [] (1,0) ([],[(0,1),(1,0),(1,1)])
recurse: 2 [] [] [(1,0)]
progress: 2 [] (0,1) ([],[(1,0),(1,1)])
recurse: 2 [] [] [(0,1)]
progress: 2 [] (0,0) ([],[(1,1)])
recurse: 2 [] [] [(0,0)]
一般情况下,跟踪语句添加评估会以严格的方式进行,因为打印出函数参数会强制它们。