我想要做一些高級的類型級編程;這個例子是我的原始程序的簡化版本。在Haskell的類型級編程中使用類型不等式
我有(Haskell)類型的表示形式。在這個例子中,我只涉及函數類型,基本類型和類型變量。
表示Type t
由一個類型變量t
參數化,以允許區分類型級別。爲了達到這個目標,我主要使用GADT。不同的類型和類型變量通過使用類型級文字來區分,因此KnownSymbol
約束和使用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)
我也制約了那種t
要的那種TypeKind
使用DataKinds和KindSignatures擴展和定義TypeKind
數據類型:
data TypeKind =
Ty Symbol
| TyVar Symbol
| (:->) TypeKind TypeKind
現在我想要實現類型的換人變量,即在類型t
中,替換爲類型變量y
,類型爲t'
的每個變量x
。替代必須在表示上以及在類型級別上執行。對於後者,我們需要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)
類型變量是最有趣的部分,因爲我們檢查符號的類型,級別和x
的y
平等。對於這一點,我們還需要一個(聚kinded)型系列,可以讓我們兩個結果之間進行選擇:
type family IfThenElse (b :: Bool) (x :: k) (y :: k) :: k where
IfThenElse True x y = x
IfThenElse False x y = y
不幸的是,這並不編譯的是,這可能是我的問題的第一個指標:
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’
啓用UndecidableInstances擴建工程,雖然如此,我們仍然定義一個函數subst
上的價值層面的工作:
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
這代碼工作完美,除了產生以下編譯錯誤的最後一行:
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
我想,問題是,我不能證明該類型的兩個符號x
和y
的不平等,並且會需要一些一種類型 - 不平等證人。這可能嗎?還是有另一種更好的方法來實現我的目標? 我不知道問題'idiomatic' Haskell type inequality和Can GADTs be used to prove type inequalities in GHC?已經回答了我的問題。任何幫助,將不勝感激。
也許這個問題可以幫助你https://stackoverflow.com/questions/17749756/idiomatic-haskell-type-inequality – Carsten
我猜你需要一個引理'要麼((x == Y): 〜:True)((x == y):〜:False)'。我不確定如何用GHC TypeLits來證明這一點,也不知道它是否可以在沒有不安全的情況下被證明... – chi
僅供參考,當你試圖做非平凡的事情時,'UndecidableInstances'通常是必需的與類型家庭。不要擔心。 – dfeuer