你可以用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 之外,还产生了 kindNat
和 type 构造函数Z :: Nat
和S :: Nat -> Nat
. 这S
与Maybe :: * -> *
- 它只是不使用所有类型的 kind ,而是您的新 kind Nat
,仅由自然数的表示形式存在。
关键是,现在您还可以定义混合类型的类型构造函数。典型的例子是Vec
:
data Vec (n :: Nat) (a :: *) where {-...-}
有种Vec :: Nat -> * -> *
。同样,T
有 kind T :: Nat -> *
。这让您可以将其与类型编码的常量长度一起使用,如果将两行不同长度的行放在一起,则会导致类型错误。
虽然这看起来非常强大,但实际上是受到限制的。为了从这种表示中得到所有东西,应该使用像Agda这样的依赖类型语言。