Монады получают fmap из Functor typeclass. Почему comonads не нужен метод cofmap, определенный в классе Cofunctor?
Почему в Haskell нет класса "Cofunctor"?
Ответ 1
Functor определяется как:
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
Cofunctor можно определить следующим образом:
class Cofunctor f where
cofmap :: (b -> a) -> (f b -> f a)
Итак, оба технически одинаковы, и почему Cofunctor не существует. "Двойное понятие" функтора вообще "по-прежнему является" функтором вообще ".
Так как Functor и Cofunctor одинаковы, обе монады и комонады определяются с помощью Functor. Но не позволяйте этому заставлять вас думать, что монады и комонады - это одно и то же, они нет.
Монада определяется (упрощается) как:
class Functor m => Monad where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
является ли comonad (опять же, упрощенный):
class Functor w => Comonad where
extract :: w a -> a
extend :: (w a -> b) -> w a -> w b
Обратите внимание на "симметрию".
Другое дело - контравариантный функтор, определяемый как:
import Data.Functor.Contravariant
class Contravariant f where
contramap :: (b -> a) -> (f a -> f b)
Ответ 2
Собственно, вы ошибаетесь: есть один!
Ответ 3
Для справки,
class Functor w => Comonad w where
extract :: w a -> a
duplicate :: w a -> w (w a)
extend :: (w a -> b) -> w a -> w b
instance Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
join :: Monad m => m (m a) -> m a
Обратите внимание, что с учетом extract и extend вы можете создавать fmap и duplicate, а при заданных return и >>= вы можете создать fmap, pure, <*> и join. Поэтому мы можем сосредоточиться только на pure + >>= и extract + extend.
Я предполагаю, что вы можете найти что-то вроде
class InverseFunctor f where
unmap :: (f a -> f b) -> a -> b
Так как класс Monad позволяет легко "вставлять вещи", но только позволяя своего рода гипотетический подход "вынимать вещи", а Comonad делает что-то противное, ваш запрос изначально звучит разумно. Тем не менее, существует значительная асимметрия между >>= и extend, которая будет мешать любой попытке определить unmap. Обратите внимание, в частности, что первый аргумент >>= имеет тип m a. Второй аргумент extend имеет тип w a — not a.