如何确定ghc为什么要查找特定类型类实例?

use*_*928 20 haskell typeclass ghc

当条件类型类实例运行得很深时,可能很难弄清楚为什么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
Run Code Online (Sandbox Code Playgroud)

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
    |       ^^^
Run Code Online (Sandbox Code Playgroud)

假设我只写了foo和的定义bar,而其他一切都是我没写过的导入代码,我可能会为ghc为什么试图找到一个MyClass1实例而感到困惑Int.这可能是我第一次听说过这个MyClass1课程,如果到目前为止我一直依赖导入的实例.如果ghc可以给我一个类型类实例链的"堆栈跟踪",那将是很好的,例如

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
Run Code Online (Sandbox Code Playgroud)

ghc有这个命令行选项吗?如果没有,我该如何调试呢?

请记住,我的真正问题比这个简单的例子复杂得多.例如

Search.hs:110:31-36: error:
    • Could not deduce (Ord
                          (Vars (DedupingMap (Rep (Index gc)) (IndexedProblem ac))))
        arising from a use of ‘search’
      from the context: (PP gc (IndexedProblem ac),
                         Show (Vars (DedupingMap (Rep (Index gc)) (IndexedProblem ac))),
                         Foldable f, MonadNotify m)
        bound by the type signature for:
                   searchIndexedReplicaProblem :: forall gc ac (f :: * -> *) (m :: *
                                                                                   -> *).
                                                  (PP gc (IndexedProblem ac),
                                                   Show
                                                     (Vars
                                                        (DedupingMap
                                                           (Rep (Index gc)) (IndexedProblem ac))),
                                                   Foldable f, MonadNotify m) =>
                                                  f (Index
                                                       (Clzs
                                                          (PartitionedProblem
                                                             gc (IndexedProblem ac))))
                                                  -> m (Maybe
                                                          (Vars
                                                             (PartitionedProblem
                                                                gc (IndexedProblem ac))))
        at Search.hs:(103,1)-(109,131)
    • In the expression: search
      In an equation for ‘searchIndexedReplicaProblem’:
          searchIndexedReplicaProblem = search
    |
110 | searchIndexedReplicaProblem = search
    |                               ^^^^^^
Run Code Online (Sandbox Code Playgroud)

PP有五种覆盖条件,我使用的是类型族和不可判定的实例,因此ghc给我错误的原因非常不明显.我可以使用哪些工具来追踪问题?

Yur*_*ras 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
Run Code Online (Sandbox Code Playgroud)

从这个转储中提取有用信息并不容易,但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
Run Code Online (Sandbox Code Playgroud)

这里d代表"深度",WD是"想要派生"的约束.所以我们有一些像所需约束的堆栈跟踪:最初我们想要MyClass3 (MyType2 (MyType1 Int)),然后我们找到了MyClass3实例MyType2,现在我们想要MyClass2 (MyType1 Int)满足它.然后我们找到了MyClass2实例MyType1,现在我们想要MyClass1 Int满足它.我知道,解释是模糊的,但这就是我对你的全部,抱歉.