Во-первых, я начал с некоторых типичных натуральных чисел на уровне типов.
{-# 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-мерную сетку. (Обобщение того, что можно найти на Оценка клеточных автоматов комонадна а>.)
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
- это тип num
-мерной сетки x
, которая "сфокусирована" на определенной точке в сетке.
Итак, я хотел сделать это комонадой и заметил, что есть потенциально полезная функция, которую я могу сделать:
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-мерную сетку m-мерных сеток в (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
выдать аналогичную ошибку типа.
Plus n Z ~ n
в контексте экземпляраFunctor
? Вам просто нужно воспроизвести это ограничение, покаn
не станет мономорфным. - person Ptharien's Flame   schedule 18.10.2012