DataKinds
私は、新しい拡張機能を使用して、サイズがタイプにエンコードされているベクトルと行列で遊んでいます。基本的には次のようになります。
data Nat = Zero | Succ Nat
data Vector :: Nat -> * -> * where
VNil :: Vector Zero a
VCons :: a -> Vector n a -> Vector (Succ n) a
Functor
ここで、とのような典型的なインスタンスが必要ですApplicative
。Functor
は簡単だ:
instance Functor (Vector n) where
fmap f VNil = VNil
fmap f (VCons a v) = VCons (f a) (fmap f v)
しかし、Applicative
インスタンスには問題があります。純粋にどのタイプを返すかがわかりません。ただし、ベクトルのサイズで帰納的にインスタンスを定義できます。
instance Applicative (Vector Zero) where
pure = const VNil
VNil <*> VNil = VNil
instance Applicative (Vector n) => Applicative (Vector (Succ n)) where
pure a = VCons a (pure a)
VCons f fv <*> VCons a v = VCons (f a) (fv <*> v)
ただし、このインスタンスはすべてのベクトルに適用されますが、型チェッカーはこれを認識しないためApplicative
、インスタンスを使用するたびに制約を実行する必要があります。
さて、これがインスタンスにのみ適用される場合Applicative
は問題にはなりませんが、このような型でプログラミングする場合は、再帰的なインスタンス宣言のトリックが不可欠であることがわかります。たとえば、TypeComposeライブラリを使用して行列を行ベクトルのベクトルとして定義すると、
type Matrix nx ny a = (Vector nx :. Vector ny) a
型クラスを定義し、再帰的なインスタンス宣言を追加して、転置と行列の乗算の両方を実装する必要があります。これにより、インスタンスが実際にはすべてのベクトルと行列に適用される場合でも、コードを使用するたびに実行しなければならない制約が大幅に増加します(制約が役に立たなくなります)。
これらすべての制約を回避する必要を回避する方法はありますか?タイプチェッカーを拡張して、そのような帰納的構造を検出できるようにすることは可能でしょうか?