Как мне определить, почему ghc ищет конкретный экземпляр класса типа? - PullRequest
0 голосов
/ 13 июня 2018

Когда экземпляры класса условного типа работают глубоко, может быть трудно понять, почему 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 пытается найти экземпляр 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

Есть ли у 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
    |                               ^^^^^^

Существует пять условий покрытия для PP, и я использую семейства типов и неразрешимые экземпляры, поэтому совершенно не очевидно, почему ghc выдает мне свою ошибку.Какие инструменты я могу использовать, чтобы отследить проблему?

1 Ответ

0 голосов
/ 13 июня 2018

Вы можете попробовать опцию -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 для MyType2, а теперь мы хотим, чтобы MyClass2 (MyType1 Int) его удовлетворил.Затем мы нашли экземпляр MyClass2 для MyType1, теперь мы хотим, чтобы MyClass1 Int удовлетворил его.Я знаю, что объяснение расплывчато, но это все, что у меня есть для вас, извините.

...