まず、いくつかの典型的なタイプレベルの自然数のものから始めました。タイプファミリーインスタンスプルーフは可能ですか?
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
data Nat = Z | S Nat
type family Plus (n :: Nat) (m :: Nat) :: Nat
type instance Plus Z m = m
type instance Plus (S n) m = S (Plus n m)
だから、n次元グリッドを表すデータ型を作成したかったのです。 (Evaluating cellular automata is comonadicで見出されるものの一般化。)
data U (n :: Nat) x where
Point :: x -> U Z x
Dimension :: [U n x] -> U n x -> [U n x] -> U (S n) x
アイデアはタイプU num x
がグリッド内の特定の点に「集束」であるx
Sのnum
次元グリッドの種類があるということです。
ufold :: (x -> U m r) -> U n x -> U (Plus n m) r
ufold f (Point x) = f x
ufold f (Dimension ls mid rs) =
Dimension (map (ufold f) ls) (ufold f mid) (map (ufold f) rs)
我々は今のn次元グリッドを向く「次元の参加」を実装することができます(n + m)次元のグリッドに変換することができます。これはグリッドのグリッドを生成するcojoin
の結果を扱うときに便利です。
dimJoin :: U n (U m x) -> U (Plus n m) x
dimJoin = ufold id
これまでのところとても良いです。私はまたFunctor
インスタンスがufold
の観点から書かれていることに気付きました。
instance Functor (U n) where
fmap f = ufold (\x -> Point (f x))
ただし、これによって型エラーが発生します。
Couldn't match type `n' with `Plus n 'Z'
しかし、私たちがいくつかのコピーパスタを揚げば、タイプエラーはなくなります。
instance Functor (U n) where
fmap f (Point x) = Point (f x)
fmap f (Dimension ls mid rs) =
Dimension (map (fmap f) ls) (fmap f mid) (map (fmap f) rs)
私はコピーパスタの味が嫌いです、私の質問はこれです。 Plus n Z
はn
とタイプシステムにどのように伝えることができますか?そして、キャッチはこれです:dimJoin
に同様の型エラーが発生するような型のファミリインスタンスを変更することはできません。あなたが必要なもの
'Functor'インスタンスのコンテキストで' Plus n Z〜n'を入力するのが助かりますか? 'n'が単形性になるまで、その制約を複製するだけです。 –