でできますDataKinds
。ただし、これは複雑すぎる可能性があります。
{-# LANGUAGE DataKinds, KindSignatures, GADTs #-}
-- requires 7.4.1, I think
data Nat = S Nat | Z
infixr 0 :.
data R (n :: Nat) where
Nil :: R Z -- like []
(:.) :: Bool -> R n -> R (S n) -- and (:)
data T (n :: Nat) = T [R n]
-- OK
test1 = T [(True :. True :. Nil), (True :. False :. Nil)]
-- will fail
test2 = T [(True :. True :. Nil), (False :. Nil)]
スマートコンストラクターを使用した @MathematicalOrchids 代替アプローチをお勧めします。
編集:何DataKinds
をしますか。
拡張機能により、コンパイラは、書き込む各データ型DataKinds
以外の*
新しい種類と、コンストラクターからこの種類に存在する新しい型を自動的に作成できます。
したがってNat
、 は単純な ADT であるだけでなく、 kind Nat
、型コンストラクターZ :: Nat
、および も生成しS :: Nat -> Nat
ます。これは、すべての種類の種類を使用するのではなく、自然数の表現のみが存在する新しい種類を使用することS
に匹敵します。Maybe :: * -> *
Nat
ポイントは、混合型の型コンストラクターも定義できるようになったことです。これの古典的な例は次のVec
とおりです。
data Vec (n :: Nat) (a :: *) where {-...-}
種類がありVec :: Nat -> * -> *
ます。同様に、T
has kind がありT :: Nat -> *
ます。これにより、型エンコードされた定数の長さで使用でき、異なる長さの 2 つの行が一緒に配置されると、型エラーが発生します。
これは非常に強力に見えますが、実際には制限されています。このような表現からすべてを引き出すには、Agdaのような依存型言語を使用する必要があります。