使用 Church 编码,可以在不使用内置 ADT 系统的情况下表示任意代数数据类型。例如,Nat
可以表示(在 Idris 中的示例)为:
-- Original type
data Nat : Type where
natSucc : Nat -> Nat
natZero : Nat
-- Lambda encoded representation
Nat : Type
Nat = (Nat : Type) -> (Nat -> Nat) -> Nat -> Nat
natSucc : Nat -> Nat
natSucc pred n succ zero = succ (pred n succ zero)
natZero : Nat
natZero n succ zero = zero
Pair
可以表示为:
-- Original type
data Pair_ : (a : Type) -> (b : Type) -> Type where
mkPair_ : (x:a) -> (y:b) -> Pair_ a b
-- Lambda encoded representation
Par : Type -> Type -> Type
Par a b = (t:Type) -> (a -> b -> t) -> t
pair : (ta : Type) -> (tb : Type) -> (a:ta) -> (b:tb) -> Par ta tb
pair ta tb a b k t = t a b
fst : (ta:Type) -> (tb:Type) -> Par ta tb -> ta
fst ta tb pair = pair ta (\ a, b => a)
snd : (ta:Type) -> (tb:Type) -> Par ta tb -> tb
snd ta tb pair = pair tb (\ a, b => b)
等等。现在,编写这些类型、构造函数、匹配器是一项非常机械的任务。我的问题是:是否可以将 ADT 表示为类型级别的规范,然后从这些规范中自动派生类型本身(即Nat
/ Par
)以及构造函数/析构函数?同样,我们可以使用这些规范来派生泛型吗?例子:
NAT : ADT
NAT = ... some type level expression ...
Nat : Type
Nat = DeriveType NAT
natSucc : ConstructorType 0 NAT
natSucc = Constructor 0 NAT
natZero : ConstructorType 1 NAT
natZero = Constructor 1 NAT
natEq : EqType NAT
natEq = Eq NAT
natShow : ShowType NAT
natShow = Show NAT
... and so on