これが私のバージョンのプログラムです。使っています
{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeFamilies #-}
そして私は持っているNat
とそのシングルトン
data Nat = Z | S Nat
data SNat :: Nat -> * where
ZZ :: SNat Z
SS :: SNat n -> SNat (S n)
あなたのInterval
タイプは、「以下」の「接尾辞」の定義として私にはよく知られています。「接尾辞」は、数値からリストにアップグレードし、それぞれS
に要素のラベルを付けると、次の定義が得られるためです。リストの接尾辞。
data Le :: Nat -> Nat -> * where
Len :: SNat n -> Le n n
Les :: Le m n -> Le m (S n)
ここに追加があります。
type family Plus (x :: Nat) (y :: Nat) :: Nat
type instance Plus Z y = y
type instance Plus (S x) y = S (Plus x y)
さて、あなたのパズルは、Les
ある値のコンストラクターを数え、Le
そのインデックス間の差のシングルトンを抽出することです。いくつかを使用して計算しようとしていると仮定するのではなく、任意のインデックス間の差を計算し、との接続を確立する関数を記述します。Le n (Plus m n)
SNat m
Le m o
Plus
Le
シングルトンが提供された、の加法的な定義は次のとおりです。
data AddOn :: Nat -> Nat -> * where
AddOn :: SNat n -> SNat m -> AddOn n (Plus m n)
Le
を意味することを簡単に確立できますAddOn
。一部のパターンマッチングは、一部のパターンマッチングであり、必要なシングルトンAddOn n o
を提供します。o
Plus m n
m
leAddOn :: Le m o -> AddOn m o
leAddOn (Len n) = AddOn n ZZ
leAddOn (Les p) = case leAddOn p of AddOn n m -> AddOn n (SS m)
より一般的には、依存型プログラミングの問題を定式化して、一致させる予定の型のインデックスに定義された関数が存在することを最小限に抑えることをお勧めします。これにより、複雑な統合を回避できます。(このような関数を緑色に着色するために使用されるエピグラム、したがって「緑色のスライムに触れないでください!」というアドバイス。)Le n o
、それは(それがポイントであるためleAddOn
)、より有益なタイプでLe n (Plus m n)
あることがわかりますが、それはかなり簡単です一致する。
さらに一般的には、問題のロジックをキャプチャする依存データ型を設定するのはごく普通の経験ですが、操作するのは非常に恐ろしいことです。これは、正しいロジックをキャプチャするすべてのデータ型が絶対に恐ろしく機能することを意味するのではなく、定義の人間工学についてもっと深く考える必要があるということです。これらの定義をきちんと理解することは、多くの人が通常の関数型プログラミングの学習経験で習得するスキルではないため、新しい学習曲線を登ることを期待してください。