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