Najpierw zacząłem od typowych rzeczy o typie naturalnym.Czy są możliwe testy typu rodzinnego?
{-# 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)
Tak więc chciałem stworzyć typ danych reprezentujący n-wymiarową siatkę. (A uogólnienie tego, co znajduje się na 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
Chodzi o to, że typ U num x
jest typ num
wymiarowej siatki x
S, który jest „skoncentrowany” na określonym punkcie w siatce .
Chciałem więc zrobić to comonad, i zauważyłem, że jest to potencjalnie użyteczna funkcja mogę zrobić:
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)
Możemy teraz zaimplementować „wymiar join”, który włącza n-wymiarowej siatki m-wymiarowe siatki w (n + m) -wymiarowej siatce, w kategoriach tego kombinatora. Przyda się to, gdy mamy do czynienia z wynikiem cojoin
, który będzie wytwarzał siatki z siatek.
dimJoin :: U n (U m x) -> U (Plus n m) x
dimJoin = ufold id
Jak dotąd tak dobrze. Zauważyłem również, że instancja Functor
może być napisana pod kątem ufold
.
instance Functor (U n) where
fmap f = ufold (\x -> Point (f x))
Jednak powoduje to błąd typu.
Couldn't match type `n' with `Plus n 'Z'
Ale jeśli wymiemy trochę makaronu do kopiowania, błąd typu zniknie.
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)
Dobrze nienawidzę smak kopiowania makaron, więc moje pytanie jest takie. Jak mogę powiedzieć systemowi typu, że Plus n Z
jest równy n
? A pułapka jest taka: nie można dokonać zmian w instancjach rodziny typów, które spowodowałyby błąd typu podobnego do dimJoin
.
Czy wstawianie 'Plus n Z ~ n' w kontekście instancji' Functor' pomaga? Wystarczy powielić to ograniczenie, aż 'n' stanie się monomorficzne. –