Les Techniques de Traçage des Contraintes
Voici le scénario: j'ai écrit un code avec une signature de type et de GHC se plaint ne pouvait pas en déduire x ~ y, pour certains x
et y
. Habituellement, vous pouvez jeter GHC un os et il suffit d'ajouter l'isomorphisme de la fonction de contraintes, mais c'est une mauvaise idée pour plusieurs raisons:
- Il ne mettent pas l'accent sur la compréhension du code.
- Vous pouvez vous retrouver avec 5 contraintes où l'on aurait suffi (par exemple, si les 5 sont implicites par un plus spécifiques contrainte)
- Vous pouvez vous retrouver avec de faux contraintes si vous avez fait quelque chose de mal ou si GHC est inutile
Je viens de passer plusieurs heures en luttant cas 3. Je suis en train de jouer avec syntaxico-2.0
, et j'ai essayé de définir un domaine indépendant de la version de share
, similaire à la version définie dans NanoFeldspar.hs
.
J'ai eu ceci:
{ -# 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
et GHC could not deduce (Internal a) ~ (Internal b)
, qui n'est certainement pas ce que j'allais pour. Donc, soit j'avais écrit un code que je n'ai pas l'intention d' (qui exige la contrainte), ou GHC voulait que la contrainte en raison d'autres contraintes que j'avais écrit.
Il s'avère que j'ai besoin d'ajouter (Syntactic a, Syntactic b, Syntactic (a->b))
à la liste de contrainte, aucun n'implique (Internal a) ~ (Internal b)
. En gros, je suis tombé sur le bon de contraintes; je n'ai pas encore de façon systématique pour les trouver.
Mes questions sont:
- Pourquoi GHC proposer cette contrainte? Nulle part dans syntaxique est-il une contrainte
Internal a ~ Internal b
, alors d'où vient GHC tirer ça? - En général, quelles techniques peuvent être utilisées pour retracer l'origine d'une contrainte qui GHC croit-il? Même pour les contraintes que je peut me découvrir moi-même, mon approche est essentiellement de force brute le chemin fautif par l'écriture physique vers le bas récursive contraintes. Cette approche est fondamentalement descendre à l'infini trou de lapin de contraintes et est à propos de la méthode la moins efficace que je peux imaginer.
- Il y a eu quelques discussions sur un type de débogueur, mais le consensus général semble montrer la logique interne de la typechecker ne va pas aider :/ Comme de droite maintenant Haskell solveur de contraintes est une merde opaque logique de la langue 🙂
- Avez-vous un lien pour que la discussion?
- Souvent, il permet seulement de supprimer la signature d'un type complètement et laisser ghci vous dire ce qu'il pense que la signature doit être.
- En quelque sorte
a
etb
sont liés au look à la signature d'un type à l'extérieur de votre contexte -a -> (a -> b) -> a
, pasa -> (a -> b) -> b
. Peut-être que c'est ça? Avec les solveurs de contraintes, ils peuvent influencer le transitive de l'égalité de n'importe où, mais les erreurs généralement preuve d'un emplacement "fermer" à l'endroit où la contrainte a été induite. Ce serait cool si @jozefg - peut-être l'annotation des contraintes avec des balises ou quelque chose, pour montrer d'où ils viennent? :s
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, votre fonction est de type incorrect; je suis assez sûr, il devrait être (sans le cadre)
a -> (a -> b) -> b
. GHC 7.10 est un peu plus utiles en soulignant que, parce que avec votre code d'origine, il se plaint d'un manque de contrainteInternal (a -> b) ~ (Internal a -> Internal a)
. Après la fixation deshare
's type, GHC 7.10 reste utile dans l'orientation de nous:Could not deduce (Internal (a -> b) ~ (Internal a -> Internal b))
Après l'ajout de la ci-dessus, nous obtenons
Could not deduce (sup ~ Domain (a -> b))
Après l'ajout, la
Could not deduce (Syntactic a)
,Could not deduce (Syntactic b)
etCould not deduce (Syntactic (a -> b))
Après l'ajout de ces trois, il est finalement typechecks; ainsi nous nous retrouvons avec
Je dirais donc que GHC n'a pas été inutile pour nous conduire.
Comme pour votre question au sujet de traçage où GHC obtient ses contraintes, vous pourriez essayer GHC drapeaux de débogage de l', en particulier,
-ddump-tc-trace
, puis lisez le journal pour voir oùInternal (a -> b) ~ t
et(Internal a -> Internal a) ~ t
sont ajoutés à laWanted
ensemble, mais qui sera assez long à lire.