Hier ist das Szenario: Ich habe Code mit einer Typensignatur geschrieben und GHC-Beschwerden konnten für einige x
und nicht auf x ~ y schließen y
. Normalerweise können Sie GHC einen Knochen werfen und einfach den Isomorphismus zu den Funktionseinschränkungen hinzufügen. Dies ist jedoch aus mehreren Gründen eine schlechte Idee:
- Das Verständnis des Codes wird nicht betont.
- Sie können mit 5 Einschränkungen enden, bei denen eine ausreichend gewesen wäre (z. B. wenn die 5 durch eine spezifischere Einschränkung impliziert werden).
- Sie können mit falschen Einschränkungen enden, wenn Sie etwas falsch gemacht haben oder wenn GHC nicht hilfreich ist
Ich habe gerade einige Stunden mit Fall 3 gekämpft. Ich spiele mit syntactic-2.0
und habe versucht, eine domänenunabhängige Version von zu definieren share
, ähnlich der in definierten Version NanoFeldspar.hs
.
Ich hatte das:
{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators #-}
import Data.Syntactic
-- Based on NanoFeldspar.hs
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi)
=> a -> (a -> b) -> a
share = sugarSym Let
und GHC could not deduce (Internal a) ~ (Internal b)
, was ich sicherlich nicht wollte. Entweder hatte ich Code geschrieben, den ich nicht beabsichtigt hatte (für den die Einschränkung erforderlich war), oder GHC wollte diese Einschränkung aufgrund einiger anderer Einschränkungen, die ich geschrieben hatte.
Es stellte sich heraus, dass ich zur (Syntactic a, Syntactic b, Syntactic (a->b))
Einschränkungsliste hinzufügen musste , von denen keine impliziert (Internal a) ~ (Internal b)
. Ich bin im Grunde auf die richtigen Einschränkungen gestoßen; Ich habe immer noch keinen systematischen Weg, sie zu finden.
Meine Fragen sind:
- Warum hat GHC diese Einschränkung vorgeschlagen? Nirgendwo in der Syntaktik gibt es eine Einschränkung
Internal a ~ Internal b
. Woher hat GHC diese? - Welche Techniken können im Allgemeinen verwendet werden, um den Ursprung einer Einschränkung zu verfolgen, die GHC für erforderlich hält? Selbst für Einschränkungen, die ich selbst entdecken kann, ist mein Ansatz im Wesentlichen brutal, den beleidigenden Pfad zu erzwingen, indem ich rekursive Einschränkungen physisch aufschreibe. Dieser Ansatz geht im Grunde genommen durch ein unendliches Kaninchenloch von Zwängen und ist ungefähr die am wenigsten effiziente Methode, die ich mir vorstellen kann.
quelle
a
undb
gebunden - schauen Sie sich die Typensignatur außerhalb Ihres Kontexts an -a -> (a -> b) -> a
nichta -> (a -> b) -> b
. Vielleicht ist es das? Mit Constraint-Solvern können sie die transitive Gleichheit überall beeinflussen , aber die Fehler zeigen normalerweise einen Ort "nahe" an dem Ort, an dem die Constraint induziert wurde. Das wäre aber cool, @jozefg - vielleicht Einschränkungen mit Tags oder so etwas zu kommentieren, um zu zeigen, woher sie kommen? : sAntworten:
Zuallererst hat Ihre Funktion den falschen Typ; Ich bin mir ziemlich sicher, dass es so sein sollte (ohne den Kontext)
a -> (a -> b) -> b
. GHC 7.10 ist etwas hilfreicher, um darauf hinzuweisen, da es sich bei Ihrem ursprünglichen Code über eine fehlende Einschränkung beschwertInternal (a -> b) ~ (Internal a -> Internal a)
. Nach der Korrekturshare
des Typs bleibt GHC 7.10 hilfreich, um uns zu führen:Could not deduce (Internal (a -> b) ~ (Internal a -> Internal b))
Nachdem wir das oben Gesagte hinzugefügt haben, erhalten wir
Could not deduce (sup ~ Domain (a -> b))
Danach Zugabe, bekommen wir
Could not deduce (Syntactic a)
,Could not deduce (Syntactic b)
undCould not deduce (Syntactic (a -> b))
Nach dem Hinzufügen dieser drei wird es schließlich typechecks; so enden wir mit
Ich würde also sagen, dass GHC uns nicht nutzlos geführt hat.
Bei Ihrer Frage zum Verfolgen, woher GHC seine Einschränkungsanforderungen bezieht, können Sie insbesondere die Debugging-Flags von GHC ausprobieren
-ddump-tc-trace
und dann das resultierende Protokoll durchlesen, um festzustellen, woInternal (a -> b) ~ t
und(Internal a -> Internal a) ~ t
zu demWanted
Satz hinzugefügt werden. Dies ist jedoch ein ziemlich langer Lesevorgang .quelle
Haben Sie dies in GHC 8.8+ versucht?
Der Schlüssel besteht darin, Typloch unter Einschränkungen zu verwenden:
_ => your difficult type
quelle