First, I started with some typical natural type number.
{-
So, I wanted to create a data type representing an n-dimensional grid. (A generalization of what is on the assessment of cellular automata is comonadic .)
data U (n :: Nat) x where Point :: x -> UZ x Dimension :: [U nx] -> U nx -> [U nx] -> U (S n) x
The idea is that the type U num x is a type of num dimensional grid x s that is "focused" on a specific point on the grid.
So, I wanted to do this comonad, and I noticed that this is a potentially useful function that I can do:
ufold :: (x -> U mr) -> U nx -> U (Plus nm) r ufold f (Point x) = fx ufold f (Dimension ls mid rs) = Dimension (map (ufold f) ls) (ufold f mid) (map (ufold f) rs)
Now we can implement a “dimensional union”, which turns an n-dimensional grid of m-dimensional grids into an (n + m) -dimensional grid in terms of this combinator. This is useful when working with the result of cojoin , which will create meshes of meshes.
dimJoin :: U n (U mx) -> U (Plus nm) x dimJoin = ufold id
So far so good. I also noticed that the Functor instance can be written in terms of ufold .
instance Functor (U n) where fmap f = ufold (\x -> Point (fx))
However, this leads to a type error.
Couldn't match type `n' with `Plus n 'Z'
But if we whip some pasta, then the type error disappears.
instance Functor (U n) where fmap f (Point x) = Point (fx) fmap f (Dimension ls mid rs) = Dimension (map (fmap f) ls) (fmap f mid) (map (fmap f) rs)
Well, I hate the taste of pasta copies, so my question is this. How can I tell the type system that Plus n Z is n ? And this is a trick: you cannot make changes to instances of a type family that will cause dimJoin create a similar type error.