例如,这是一个函数:
iffthen :: [String] -> Parser String
iffthen a = do
x <- symbol (head a)
y <- booleana (head (tail a))
z <- symbol (head (tail (tail a)))
k <- assignP (head (tail (tail (tail a))))
l <- symbol (head (tail (tail (tail (tail a)))))
m <- assignP (head (tail (tail (tail (tail (tail a))))))
return k
我需要看看每个指令真正做什么
您可以使用Debug.Trace
的trace :: String -> a -> a
,或相关函数,如traceShowId :: Show a => a -> a
。此函数基本上在函数被计算时打印附加的String
参数,并返回函数的结果。
因此,对于某些可以打印的内容,我们可以附加此类trace
功能,从而打印信息。请注意,Haskell中的调试通常与命令式语言中的调试不同,主要是由于懒惰:通常不计算函数,除非我们需要结果。因此,这意味着某些函数永远不会被评估,或者这些函数在我们构造该函数很久之后才被评估。
除了你的函数,我建议在这里使用模式匹配,并消除未使用变量的噪音:
iffthen :: [String] -> Parser String
iffthen(ifs : cond : thens : val1 : elses : val2 : _)= do
symbolifs
booleanacond
symbolthens
k <- assignPval1
symbolelses
assignPval2
return k
(鉴于我相应地解释了您想要的内容,并且ifs
、thens
、elses
是符号,cond
是条件,val1
和val2
是if
-then
-else
表达式的值(。
最好不要使用列表(因为在编译时不能保证元素的数量(,从而使用特定参数构造一个 sperate 类型。
除了trace
,请查看traceM :: Applicative f => String -> f ()
和traceShowM :: (Show a, Applicative f) => a -> f ()
。
这些是putStrLn
的方便替代品,print
在任何monad上下文中都可用:
iffthen :: [String] -> Parser String
iffthen a = do
x <- symbol (head a)
traceM "booleana"
y <- booleana (head (tail a))
traceM "symbol 1"
z <- symbol (head (tail (tail a)))
traceM "assignP 1"
k <- assignP (head (tail (tail (tail a))))
traceM "symbol 2"
l <- symbol (head (tail (tail (tail (tail a)))))
traceM "assignP 2"
m <- assignP (head (tail (tail (tail (tail (tail a))))))
return k
如果您对每个解析器的结果感兴趣,请将traceShowId
与<$>
等一起使用。
iffthen :: [String] -> Parser String
iffthen a = do
x <- symbol (head a)
y <- traceShowId <$> booleana (head (tail a))
z <- traceShowId <$> symbol (head (tail (tail a)))
k <- traceShowId <$> assignP (head (tail (tail (tail a))))
l <- traceShowId <$> symbol (head (tail (tail (tail (tail a)))))
m <- traceShowId <$> assignP (head (tail (tail (tail (tail (tail a))))))
return k
ghci
确实有一个步进调试器。由于Haskell代码往往是功能性和懒惰的,我认为它有时会导致惊喜。Emacshaskell-mode
曾经有调试器集成...我想我遇到了该集成作者的评论,指出调试器在某些方面有问题,但现在找不到它。但是我已经在一些基本示例中尝试了调试器,它的工作原理如广告所示。