高度な型レベルプログラミングをしようとしています。この例は私の元のプログラムの縮小バージョンです。Haskellの型レベルプログラミングで型不等式を使用する
私は(ハスケル)型の表現をしています。この例では、関数型、基本型、型変数のみを扱います。
表現Type t
は、1つのタイプ変数t
によってパラメータ化され、タイプレベルの差別化も可能です。これを達成するために、主にGADTを使用しています。異なる型と型変数は、型レベルのリテラルを使用することによって区別されるため、KnownSymbol
制約とProxy
の使用が区別されます。
{-# 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)
私はDataKindsとKindSignatures拡張機能を使用してTypeKind
データ型を定義することによって、一種TypeKind
であることがt
の種類をも制限されている:
data TypeKind =
Ty Symbol
| TyVar Symbol
| (:->) TypeKind TypeKind
今、私はタイプの置換を実装します変数、すなわちタイプt
の中で、変数x
をタイプ変数y
のタイプt'
と等しいすべての変数に置き換えます。代入は、表現およびタイプレベルで実装されなければなりません。後者の場合、我々はTypeFamilies必要があります:私たちはタイプレベルのシンボルx
とy
の平等をチェックするため
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)
を型変数は、興味深い部分です。このために、我々はまた、(ポリkinded)を必要とする私たちは二つの結果の間で選択することができます家族のように入力します。
type family IfThenElse (b :: Bool) (x :: k) (y :: k) :: k where
IfThenElse True x y = x
IfThenElse False x y = y
残念ながら、これは私の問題の最初の指標であるかもしれない、まだコンパイルされません。
UndecidableInstances拡張を有効にする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’
は、しかし、働くので、私たちは価値のレベルで動作する機能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
私はこの問題は、私は2つのシンボル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'でどのように証明されているのか、' unsafe'というものがないと証明できないのかどうかはわかりません。 – chi
FYI、 'UndecidableInstances'は、タイプファミリーを持つ。ご心配なく。 – dfeuer