J'essaie d'effectuer une programmation avancée au niveau du type; l'exemple est une version réduite de mon programme original.Utilisation de l'inégalité de type dans la programmation au niveau du type dans Haskell
J'ai une représentation des types (Haskell). Dans cet exemple, je ne couvre que les types de fonctions, les types de base et les variables de type.
La représentation Type t
est paramétrée par une variable de type t
pour permettre également une différenciation sur le niveau type. Pour y parvenir, j'utilise principalement des GADT. Différents types et variables de type sont différenciés en utilisant des littéraux au niveau du type, ainsi la contrainte KnownSymbol
et l'utilisation de Proxy
s.
{-# LANGUAGE GADTs, TypeOperators, DataKinds, KindSignatures, TypeFamilies, PolyKinds #-}
import GHC.TypeLits
import Data.Proxy
import Data.Type.Equality
data Type :: TypeKind -> * where
TypeFun :: Type a -> Type b -> Type (a :-> b)
Type :: KnownSymbol t => Proxy t -> Type (Ty t)
TypeVar :: KnownSymbol t => Proxy t -> Type (TyVar t)
J'ai également limité le genre de t
être de type TypeKind
en utilisant les extensions DataKinds et KindSignatures et définir le type de données TypeKind
:
data TypeKind =
Ty Symbol
| TyVar Symbol
| (:->) TypeKind TypeKind
Maintenant, je veux mettre en œuvre des substitutions de type variables, c'est-à-dire en substituant, dans un type t
, chaque variable qui est égale à une variable de type y
, avec le type t'
. La substitution doit être implémentée sur la représentation, ainsi que sur le niveau type. Pour ce dernier, nous avons besoin TypeFamilies:
type family Subst (t :: TypeKind) (y :: Symbol) (t' :: TypeKind) :: TypeKind where
Subst (Ty t) y t' = Ty t
Subst (a :-> b) y t' = Subst a y t' :-> Subst b y t'
Subst (TyVar x) y t' = IfThenElse (x == y) t' (TyVar x)
Les variables de type sont la partie intéressante, parce que nous vérifions pour l'égalité des symboles x
et y
au niveau du type. Pour cela, nous avons également besoin d'un (poly-kinded) le type de famille qui nous permet de choisir entre deux résultats:
type family IfThenElse (b :: Bool) (x :: k) (y :: k) :: k where
IfThenElse True x y = x
IfThenElse False x y = y
Malheureusement, cela ne compile pas encore, ce qui pourrait être le premier indicateur de mon problème:
Nested type family application
in the type family application: IfThenElse (x == y) t' ('TyVar x)
(Use UndecidableInstances to permit this)
In the equations for closed type family ‘Subst’
In the type family declaration for ‘Subst’
Activation de l'extension UndecidableInstances fonctionne, bien que, si nous continuons à définir une fonction subst
qui fonctionne sur la valeur de niveau:
subst :: (KnownSymbol y) => Type t -> Proxy (y :: Symbol) -> Type t' -> Type (Subst t y t')
subst (TypeFun a b) y t = TypeFun (subst a y t) (subst b y t)
subst [email protected](Type _) _ _ = t
subst [email protected](TypeVar x) y t'
| Just Refl <- sameSymbol x y = t'
| otherwise = t
Cette code fonctionne parfaitement, à l'exception de la dernière ligne qui produit l'erreur de compilation suivante:
Could not deduce (IfThenElse
(GHC.TypeLits.EqSymbol t1 y) t' ('TyVar t1)
~ 'TyVar t1)
from the context (t ~ 'TyVar t1, KnownSymbol t1)
bound by a pattern with constructor
TypeVar :: forall (t :: Symbol).
KnownSymbol t =>
Proxy t -> Type ('TyVar t),
in an equation for ‘subst’
at Type.hs:29:10-18
Expected type: Type (Subst t y t')
Actual type: Type t
Relevant bindings include
t' :: Type t' (bound at Type.hs:29:23)
y :: Proxy y (bound at Type.hs:29:21)
x :: Proxy t1 (bound at Type.hs:29:18)
subst :: Type t -> Proxy y -> Type t' -> Type (Subst t y t')
(bound at Type.hs:27:1)
In the expression: t
In an equation for ‘subst’:
subst [email protected](TypeVar x) y t'
| Just Refl <- sameSymbol x y = t'
| otherwise = t
Je suppose que le problème est que je ne peux pas prouver l'inégalité des types des deux symboles x
et y
, et aurais besoin type de témoin de type-inégalité. Est-ce possible? Ou y a-t-il une autre meilleure façon d'atteindre mon objectif? Je ne sais pas dans quelle mesure les questions 'idiomatic' Haskell type inequality et Can GADTs be used to prove type inequalities in GHC? répondent déjà à ma question. Toute aide serait appréciée.
peut-être cette question peut vous aider à https://stackoverflow.com/questions/17749756/idiomatic-haskell-type-inequality – Carsten
Je suppose que vous avez besoin d'un lemme 'Soit ((x == y): ~: Vrai) ((x == y): ~: Faux) '. Je ne suis pas sûr comment cela peut être prouvé avec GHC 'TypeLits', ni si c'est prouvable du tout sans substance' unsafe' ... – chi
FYI, 'UndecidableInstances' est généralement nécessaire lorsque vous essayez de faire des choses non triviales avec des familles de type. Ne t'en fais pas pour ça. – dfeuer