Ich versuche, einige erweiterte Typ-Level-Programmierung zu tun; Das Beispiel ist eine reduzierte Version meines ursprünglichen Programms.Verwendung von Typ-Ungleichheit innerhalb der Typenebene Programmierung in Haskell
Ich habe eine Darstellung von (Haskell) Typen. In diesem Beispiel behandle ich nur Funktionstypen, Grundtypen und Typvariablen.
Die Darstellung Type t
ist durch eine Typvariable t
parametriert, um auch eine Unterscheidung auf der Typ-Ebene zu ermöglichen. Um dies zu erreichen, verwende ich hauptsächlich GADTs. Unterschiedliche Typen und Typvariablen werden unterschieden, indem Literale auf Typenebene verwendet werden, also die KnownSymbol
Einschränkung und die Verwendung von 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)
Ich habe beschränkt auch die Art der t
von Art TypeKind
sein, indem sie die DataKinds und KindSignatures Erweiterungen und Definition der TypeKind
Datentyp:
data TypeKind =
Ty Symbol
| TyVar Symbol
| (:->) TypeKind TypeKind
Jetzt möchte ich Substitutionen von Typ implementieren Variablen, dh Ersetzen innerhalb einer Art t
jede Variable x
, die gleich einer Typvariable y
ist, mit Typ t'
. Die Substitution muss sowohl auf der Repräsentation als auch auf der Typ-Ebene implementiert werden. Für letzteren müssen wir 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)
Die Typvariablen sind der interessante Teil, weil wir für die Gleichheit der Symbole überprüfen x
und y
auf der Typebene. Dafür brauchen wir auch einen (Poly-kinded) -Typ-Familie, die wir zwischen zwei Ergebnissen auswählen kann:
type family IfThenElse (b :: Bool) (x :: k) (y :: k) :: k where
IfThenElse True x y = x
IfThenElse False x y = y
Leider kompiliert, dies noch nicht, was der erste Indikator für mein Problem sein könnte:
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’
die UndecidableInstances Erweiterung Aktivieren funktioniert, obwohl, so dass wir auch weiterhin eine Funktion subst
definieren, die auf dem Wert-Ebene funktioniert:
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
diese Code funktioniert perfekt, mit Ausnahme der letzten Zeile, das die folgenden Kompilierungsfehler erzeugt:
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
Ich denke, dass das Problem ist, dass ich nicht die Ungleichheit der Typen der beiden Symbole x
und y
beweisen kann, und muß einig Art von Typ-Ungleichheit Zeuge. Ist das möglich? Oder gibt es einen anderen, besseren Weg, um mein Ziel zu erreichen? Ich weiß nicht, in welchem Umfang die Fragen 'idiomatic' Haskell type inequality und Can GADTs be used to prove type inequalities in GHC? bereits meine Frage beantworten. Jede Hilfe wäre willkommen.
vielleicht diese Frage kann Ihnen helfen https://stackoverflow.com/questions/17749756/idiomatic-haskell-type-inequality – Carsten
Ich denke, Sie brauchen ein Lemma 'Entweder ((x == y): ~: True) ((x == y): ~: Falsch) '. Ich bin mir nicht sicher, wie das mit GHC 'TypeLits' bewiesen werden kann, oder ob es überhaupt beweisbar ist ohne 'unsicheren' Kram ... – chi
FYI, 'UndecidableInstances' ist normalerweise notwendig, wenn Sie nicht-triviale Dinge tun wollen mit Typfamilien. Mach dir keine Sorgen darüber. – dfeuer