В предыдущем ответе Петр Пудлак определил класс CFunctor
для функторов, отличных от тех, что от Hask до Hask. Переписывая его немного с помощью семейств типов, он выглядит как
class CFunctor f where
type Dom f :: * -> * -> * -- domain category
type Cod f :: * -> * -> * -- codomain category
cmap :: Dom f a b -> Cod f (f a) (f b) -- map morphisms across categories
с экземплярами, которые выглядят, например,
instance CFunctor Maybe where
type Dom Maybe = (->) -- domain is Hask
type Cod Maybe = (->) -- codomain is also Hask
cmap f = \m -> case m of
Nothing -> Nothing
Just x -> Just (f x)
В теории категорий всякий раз, когда F: C → D - функтор, а G: D → E - функтор, то композиция GF: C → E также является функтором.
Я хотел бы выразить это в Haskell. Поскольку я не могу написать instance CFunctor (f . g)
, я ввожу класс-оболочку:
newtype Wrap g f a = Wrap { unWrap :: g (f a) }
При написании экземпляра CFunctor
я добираюсь до
instance (CFunctor f, CFunctor g, Cod f ~ Dom g) => CFunctor (Wrap g f) where
type Dom (Wrap g f) = Dom f
type Cod (Wrap g f) = Cod g
cmap = undefined
но я не могу понять, что должно быть реализовано cmap
. Любые советы?
PS конечная причина всего этого - также ввести класс Adjunction
с методами unit
и counit
, а затем автоматически выводить экземпляры монады из адъюнкций. Но сначала мне нужно показать компилятору, что композиция из двух функторов также является функтором.
Я знаю, что я мог бы использовать cmap.cmap
для объекта типа g (f a)
, и это сработало бы, но это похоже на обман. Конечно, функтор - это просто функтор, и компилятор не должен иметь знать, что это фактически композиция из двух других функторов?