Ответ 1
Какой может быть наиболее последовательный доступный путь, начиная с Category
, где вполне естественно иметь ограничение на объекты: Object!
class Category k where
type Object k :: * -> Constraint
id :: Object k a => k a a
(.) :: (Object k a, Object k b, Object k c)
=> k b c -> k a b -> k a c
Затем мы определяем функторы, подобные как это делает Эдвард
class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
fmap :: (Object r a, Object t (f a), Object r b, Object t (f b))
=> r a b -> t (f a) (f b)
Все это прекрасно работает и реализовано в библиотеке ограниченных категорий, которая - стыдно за меня! - все еще не находится в Hackage.
Applicative
, к сожалению, немного менее прост. Математически это моноидальные функторы, поэтому нам сначала нужно > моноидальные категории. categories
имеет этот класс, но он не работает с версией на основе ограничений, потому что наши объекты всегда имеют что-то вроде *
с ограничением. Итак, что я сделал, это Curry
класс, который приближает это.
Затем мы можем сделать Monoidal
functors:
class (Functor f r t, Curry r, Curry t) => Monoidal f r t where
pure :: (Object r a, Object t (f a)) => a `t` f a
fzipWith :: (PairObject r a b, Object r c, PairObject t (f a) (f b), Object t (f c))
=> r (a, b) c -> t (f a, f b) (f c)
Это фактически эквивалентно Applicative
, когда у нас есть правильные замкнутые декартовы категории. В версии с ограниченными категориями, к сожалению, подписи выглядят очень ужасно:
(<*>) :: ( Applicative f r t
, MorphObject r a b, Object r (r a b)
, MorphObject t (f a) (f b), Object t (t (f a) (f b)), Object t (f (r a b))
, PairObject r (r a b) a, PairObject t (f (r a b)) (f a)
, Object r a, Object r b, Object t (f a), Object t (f b))
=> f (r a b) `t` t (f a) (f b)
Тем не менее, это действительно работает - для безусловного случая, duh! Я еще не нашел удобный способ использовать его с нетривиальными ограничениями.
Но опять же, Applicative
эквивалентно Monoidal
, и это можно использовать, как показано в пример Set
.