在Haskell中进行简单的调试

Jac*_*aie 11 debugging haskell

我是Haskell的新手.以前我用Python和Java编程.当我调试一些代码时,我习惯用print代码中间的语句乱丢它.但是,在Haskell中这样做会改变语义,我将不得不将我的函数签名更改为具有IO东西的那些.Haskellers如何处理这个问题?我可能会遗漏一些明显的东西.请指教.

sin*_*law 8

读这个.您可以使用Debug.Trace.trace代替打印语句.

  • 你如何使用“trace”真是令人困惑。我无法让它工作,而且该文档真的很糟糕。 (6认同)

Ada*_*rke 6

其他答案将官方 docoHaskell wiki链接起来,但是如果您已经回答了这个答案,那么假设您出于任何原因放弃了这些答案。在维基还具有使用斐波那契,我发现更容易的例子。这是一个刻意的基本示例,可能会有所帮助。

假设我们从这个非常简单的函数开始,出于重要的业务原因,它向字符串添加“bob”,然后将其反转。

bobreverse x = reverse ("bob" ++ x)
Run Code Online (Sandbox Code Playgroud)

GHCI 中的输出:

> bobreverse "jill"
"llijbob"
Run Code Online (Sandbox Code Playgroud)

我们不知道这怎么可能会出错,但接近它的东西,所以我们添加了调试。

> bobreverse "jill"
"llijbob"
Run Code Online (Sandbox Code Playgroud)

输出:

> bobreverse "jill"
"DEBUG: bobreverse "jill"
llijbob"
Run Code Online (Sandbox Code Playgroud)

我们使用show只是为了确保x在输出之前正确转换为字符串。我们还添加了一些括号以确保参数正确分组。

总之,该trace函数是一个装饰器,它打印第一个参数并返回第二个参数。它看起来像一个纯函数,所以你不需要IO在函数中引入或其他签名来使用它。它通过作弊来做到这一点,如果您好奇的话,这在上面的链接文档中有进一步的解释。

  • 非常重要的是要注意:使用“trace”时要考虑到编译器。例如,用“trace”包装未使用的值,或者将值分配给“where”块中的变量(编译器可以简单地替换输出表达式中的变量),或者将跟踪分配给未使用的值......将所有这些都会导致“trace”被忽略。*来自文档:您必须记住,由于惰性评估,您的跟踪只有在需要它们包装的值时才会打印。* (4认同)

gat*_*ado 5

我能够创建一个双重个性IO/ STmonad类型类,它会在输入monadic计算时打印调试语句IO,当它被输入时,它们会打印出来ST.演示和代码在这里:Haskell - 双重人格IO/ST monad?.

当然Debug.Trace更多的是瑞士军刀,特别是当用一个有用的特殊情况包裹时,

trace2 :: Show a => [Char] -> a -> a
trace2 name x = trace (name ++ ": " ++ show x) x
Run Code Online (Sandbox Code Playgroud)

可以使用像 (trace2 "first arg" 3) + 4

编辑

如果你想要源位置,你可以让它更加漂亮

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import Language.Haskell.TH.Syntax as TH
import Debug.Trace

withLocation :: Q Exp -> Q Exp
withLocation f = do
    let error = locationString =<< location
    appE f error
    where
        locationString :: Loc -> Q Exp
        locationString loc = do
            litE $ stringL $ formatLoc loc

formatLoc :: Loc -> String
formatLoc loc = let file = loc_filename loc
                    (line, col) = loc_start loc
                in concat [file, ":", show line, ":", show col]

trace3' (loc :: String) msg x =
    trace2 ('[' : loc ++ "] " ++ msg) x
trace3 = withLocation [| trace3' |]
Run Code Online (Sandbox Code Playgroud)

然后,在一个单独的文件[来自上面的定义],你可以写

{-# LANGUAGE TemplateHaskell #-}
tr3 x = $trace3 "hello" x
Run Code Online (Sandbox Code Playgroud)

并测试出来

> tr3 4
[MyFile.hs:2:9] hello: 4
Run Code Online (Sandbox Code Playgroud)


bzn*_*bzn 2

您可以使用Debug.Trace来实现这一点。

  • 如何使用它?没有一个文档是有用的。 (4认同)