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:

  1. Il ne mettent pas l'accent sur la compréhension du code.
  2. 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)
  3. 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:

  1. Pourquoi GHC proposer cette contrainte? Nulle part dans syntaxique est-il une contrainte Internal a ~ Internal b, alors d'où vient GHC tirer ça?
  2. 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 et b sont liés au look à la signature d'un type à l'extérieur de votre contexte - a -> (a -> b) -> a, pas a -> (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
InformationsquelleAutor crockeea | 2014-05-03