当条件类型类实例运行得很深时,可能很难弄清楚为什么ghc抱怨缺少类型类实例。例如:
class MyClass1 c
class MyClass2 c
class MyClass3 c
data MyType1 a
data MyType2 a
instance MyClass1 a => MyClass2 (MyType1 a)
instance MyClass2 a => MyClass3 (MyType2 a)
foo :: (MyClass3 c) => c
foo = undefined
bar :: MyType2 (MyType1 Int)
bar = foo
GHC出现以下错误:
Example.hs:149:7-9: error:
• No instance for (MyClass1 Int) arising from a use of ‘foo’
• In the expression: foo
In an equation for ‘bar’: bar = foo
|
149 | bar = foo
| ^^^
假设我只写了foo
和bar
的定义,其他一切都是我没写的导入代码,我可能会为ghc试图找到{{{ 1}} MyClass1
的实例。这可能是我第一次听说Int
类,如果到目前为止我一直依赖导入的实例。如果ghc可以给我一个类型类实例链的“堆栈跟踪”,例如
MyClass1
ghc是否有一个命令行选项?如果没有,我该如何调试呢?
请记住,我的真正问题比这个简单的例子复杂得多。 e.g。
Sought (MyClass2 (MyType1 Int)) to satisfy (MyClass3 (MyType2 (MyType1 Int))) from conditional type class instance OtherModule.hs:37:1-18
Sought (MyClass1 Int) to satisfy (MyClass2 (MyType1 Int)) from conditional type class instance OtherModule.hs:36:1-18
PP有五种覆盖条件,我正在使用类型族和不可判定的实例,因此ghc给我错误的原因非常不明显。我可以使用哪些工具来追踪问题?
答案 0 :(得分:7)
你可以试试-ddump-cs-trace
选项,虽然它的目的是在调试约束解决代码时帮助GHC开发人员,但它也可能对你有用。以下是您的示例的输出:
Step 1[l:2,d:0] Kept as inert:
[G] $dMyClass3_a1rt {0}:: MyClass3 c_a1rs[sk:2]
Step 2[l:2,d:0] Dict equal (keep):
[WD] $dMyClass3_a1rv {0}:: MyClass3 c_a1rs[sk:2]
Constraint solver steps = 2
Step 1[l:1,d:0] Top react: Dict/Top (solved wanted):
[WD] $dMyClass3_a2uc {0}:: MyClass3 (MyType2 (MyType1 Int))
Step 2[l:1,d:1] Top react: Dict/Top (solved wanted):
[WD] $dMyClass2_a2up {1}:: MyClass2 (MyType1 Int)
Step 3[l:1,d:2] Kept as inert:
[WD] $dMyClass1_a2uq {2}:: MyClass1 Int
Step 4[l:2,d:0] Kept as inert:
[G] $dMyClass3_a1rB {0}:: MyClass3 c_a1rz[sk:2]
Step 5[l:2,d:0] Wanted CallStack IP:
[WD] $dIP_a2u8 {0}:: ?callStack::GHC.Stack.Types.CallStack
Step 6[l:2,d:0] Kept as inert:
[WD] $dIP_a2uA {0}:: ?callStack::GHC.Stack.Types.CallStack
Step 7[l:2,d:0] Kept as inert:
[G] $dMyClass2_a2uh {0}:: MyClass2 a_a2ug[ssk:2]
Step 8[l:2,d:0] Kept as inert:
[G] $dMyClass1_a2ul {0}:: MyClass1 a_a2uk[ssk:2]
Constraint solver steps = 8
从此转储中提取有用信息并不容易,但AFAIK是目前唯一可用的选项。相关门票很少:13443,15044
增加: 我将尝试解释转储的含义。我实际上并不熟悉GHC内部,所以这只是我(可能是错误的)理解。
相关位是下一个:
Step 1[l:1,d:0] Top react: Dict/Top (solved wanted):
[WD] $dMyClass3_a2uc {0}:: MyClass3 (MyType2 (MyType1 Int))
Step 2[l:1,d:1] Top react: Dict/Top (solved wanted):
[WD] $dMyClass2_a2up {1}:: MyClass2 (MyType1 Int)
Step 3[l:1,d:2] Kept as inert:
[WD] $dMyClass1_a2uq {2}:: MyClass1 Int
此处d
代表“深度”,WD
是“想要派生”的约束。所以我们有一些想要约束的堆栈跟踪:最初我们想要MyClass3 (MyType2 (MyType1 Int))
,然后我们找到MyClass3
的{{1}}实例,现在我们希望MyType2
满足它。然后我们找到MyClass2 (MyType1 Int)
的{{1}}实例,现在我们希望MyClass2
满足它。我知道,解释是模糊的,但这就是我对你的全部,抱歉。