Voici un lambda-calcul non typé dont les termes sont indexés par leurs variables libres. J'utilise la bibliothèque singletons
pour les valeurs singleton de chaînes de niveau de type. Un Var
introduit une variable libre. Une abstraction lambda lie une variable qui apparaît libre dans le corps (s'il y en a une qui correspond). Les applications joignent les variables libres des deux parties de l'expression, supprimant les doublons (donc les variables libres de x y
sont x
et y
, alors que les variables libres de x x
sont juste). Je rédigeai ces types de familles:Pourquoi GHC ne réduira-t-il pas ma famille de caractères?
type family Remove x xs where
Remove x '[] = '[]
Remove x (x ': xs) = Remove x xs
Remove x (y ': xs) = y ': Remove x xs
type family Union xs ys where
Union xs ys = Nub (xs :++ ys)
type family xs :++ ys where
'[] :++ ys = ys
(x ': xs) :++ ys = x ': (xs :++ ys)
type family Nub xs where
Nub xs = Nub' '[] xs
type family Nub' seen xs where
Nub' seen '[] = '[]
Nub' seen (x ': xs) = If (Elem x seen) (Nub' seen xs) (Nub' (x ': seen) (x ': xs))
type family If c t f where
If True t f = t
If False t f = f
type family Elem x xs where
Elem x '[] = False
Elem x (x ': xs) = True
Elem x (y ': xs) = Elem x xs
j'ai testé ceci à l'invite interactive:
ghci> :t Var (sing :: Sing "x")
Var (sing :: Sing "x") :: Expr '["x"] -- good
ghci> :t (Lam (sing :: Sing "x") (Var (sing :: Sing "x")))
(Lam (sing :: Sing "x") (Var (sing :: Sing "x")))
:: Expr (Remove "x" '["x"]) -- not so good
Je fus surpris d'apprendre que le type de la fonction d'identité \x. x
est Expr (Remove "x" '["x"])
, pas Expr '[]
. GHC ne semble pas disposé à évaluer la famille de caractères Remove
. J'ai expérimenté un peu plus et a appris que ce n'est pas un problème avec ma famille de type en tant que tel - GHC est heureux de le réduire dans ce cas:
ghci> :t (Proxy :: Proxy (Remove "x" '["x"]))
(Proxy :: Proxy (Remove "x" '["x"])) :: Proxy '[]
donc: Pourquoi ne GHC réduire Remove "x" '["x"]
à '[]
quand je interroger le type de mon GADT? En général, quand le vérificateur de type va-t-il ou ne va-t-il pas évaluer une famille de types? Y a-t-il des heuristiques que je peux utiliser pour éviter d'être surpris par son comportement?
je lis « Pourquoi ne GHC réduire ma famille? "Et cela a semblé très brutal. –
@JoachimBreitner Même les meilleurs compilateurs ne peuvent pas faire tout ce que vous voulez –
Je suspecterais des définitions qui se chevauchent dans 'Remove', basé sur https://wiki.haskell.org/GHC/Type_families#Closed_family_simplification. Vous auriez probablement besoin d'une contrainte, en observant que les types sont inégaux – phadej