Почему в Haskell нет класса "Cofunctor"?
Монады получают fmap
из Functor
typeclass. Почему comonads не нужен метод cofmap
, определенный в классе 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
Собственно, вы ошибаетесь: есть один!
https://hackage.haskell.org/package/acme-cofunctor
Ответ 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
.