Haskell: 查找不完整记录构建的来源

Haskell: Finding the source of incomplete record construction

我正在尝试在 Haskell 中调试一个大型、复杂的程序,该程序并不是我自己完全编写的。

我正在尝试打印我的数据结构来诊断错误,但是当我这样做时,我收到以下错误:error: Prelude.undefined。如您所见,此错误信息非常少。

我有理由相信这是来自我 "partially" 初始化的记录,我在其中尝试访问一个值尚未设置的字段。

该程序(编译器)分布在两个 cabal 项目、一个库和一个使用该库的可执行文件中。这使得使用 GHCI/cabal-repl 进行调试变得困难:我不能 运行 在可执行文件上使用 GHCi,因为它不是错误的根源,但是重新创建可执行文件提供给库的输入太复杂了手动。

我想知道:我能做些什么来获得更多关于错误记录创建位置、错误来源的字段等的信息。是否有 RTS 选项或我可以用来提供的东西有关错误输出的更多信息?

如果您在 cabal 文件的 ghc-options 中使用 -Wall,它会给出不完整记录的警告。

module Foo where
data Bar = Bar { bar :: String, baz :: String }
f = Bar { baz = "foo" }

Foo.hs:5:5: Warning:
  Fields of ‘Bar’ not initialised: bar
  In the expression: Bar {baz = "foo"}
  In an equation for ‘f’: f = Bar {baz = "foo"}
Ok, modules loaded: Foo.

使用 -Wall(或 -Werror)进行编译是寻找未初始化字段来源的良好开端。但是,它可能不是错误的来源。缺少记录字段初始化有特定的错误消息:

Prelude> data A = A { a :: Int } deriving Show
Prelude> A {}
A {a = *** Exception: <interactive>:11:1-4: Missing field in record construction a

如果给记录字段添加严格注解,编译时会报错:

Prelude> data A = A { a :: !Int } deriving Show
Prelude> let a = A { }

<interactive>:26:9:
    Constructor ‘A’ does not have the required strict field(s): a
    In the expression: A {}
    In an equation for ‘a’: a = A {}

查找错误源的另一个选项是在启用分析的情况下进行编译并传递 -xc RTS 标志。

来自 GHC 用户指南: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runtime-control.html

-xc (Only available when the program is compiled for profiling.) When an exception is raised in the program, this option causes a stack trace to be dumped to stderr.

This can be particularly useful for debugging: if your program is complaining about a head [] error and you haven't got a clue which bit of code is causing it, compiling with -prof -fprof-auto and running with +RTS -xc -RTS will tell you exactly the call stack at the point the error was raised.

The output contains one report for each exception raised in the program (the program might raise and catch several exceptions during its execution), where each report looks something like this:

*** Exception raised (reporting due to +RTS -xc), stack trace: GHC.List.CAF --> evaluated by: Main.polynomial.table_search,
called from Main.polynomial.theta_index, called from Main.polynomial, called from Main.zonal_pressure, called from Main.make_pressure.p, called from Main.make_pressure, called from Main.compute_initial_state.p, called from Main.compute_initial_state, called from Main.CAF ...