Реальна ли концепция чередующегося гомоморфизма?

Мне нужен следующий класс функций:

class InterleavedHomomorphic x where
  interleaveHomomorphism :: (forall a . f a -> g a) -> x f -> x g

Очевидно, придуманное мной имя никоим образом не является официальным термином для чего-либо, а приведенный выше класс типа не очень элегантен. Это концепция, у которой есть имя, или даже реализация в какой-то библиотеке? Есть ли более разумный способ сделать это?


Цель этой функции состояла бы в том, чтобы у меня был некоторый контекст f, который аннотирует некоторые данные (Foo и Bar - это просто случайные примерные структуры данных для этого вопроса):

data Foo f = One (f (Bar f)) | Product (f (Foo f)) (f (Foo f))
data Bar f = Zero | Succ (f (Bar f))

Я хотел бы преобразовать контекст данных полиморфным способом; только зная гомоморфизм между контекстами и не заботясь (обязательно) о самих данных. Это можно сделать, указав instance InterleavedHomomorphic Foo и instance InterleavedHomomorphic Bar в приведенном выше примере.


person dflemstr    schedule 06.06.2014    source источник


Ответы (3)


Итак, если f и g - правильные функторы, forall a. f a -> g a - естественное преобразование. Мы могли бы сделать его немного красивее:

type f ~> g = forall a. f a -> g a

Подобные естественные преобразования позволяют сформировать категорию функторов Haskell, так что у вас есть функтор из этой категории в некоторую другую категорию.

Следуя шагам обычных функторов Haskell, возможно, имеет смысл сделать x эндофунктором, отображающим функторы на другие функторы. Это похоже, но не идентично тому, что у вас есть:

class FFunctor x where
  ffmap :: (f ~> g) -> (x f ~> x g)

Однако в вашем случае x f и x g не являются функторами, а x f -> x g - это обычная функция, а не естественное преобразование. Тем не менее, картина достаточно близка, чтобы показаться интригующей.

Имея это в виду, кажется, что x все еще является примером функтора, только между двумя разными категориями. Он переходит из категории Функторов в категорию x с различными структурами. Каждый возможный x, как и Foo, образует категорию с такими объектами, как Foo [] и Foo Maybe, и преобразованиями между ними (Foo [] -> Foo Maybe). Ваша interleaveHomomorphism функция "поднимает" естественные преобразования в эти x-morphisms, точно так же, как fmap "поднимает" обычные (a -> b) функции в функции в образе функтора (f a -> f b).

Так что да: ваш класс типов - это функтор, как и Functor, за исключением двух разных категорий. Я не знаю конкретного имени для него, в основном потому, что я не знаю конкретного имени для таких конструкций, как x.

В общем, я даже не уверен, что конкретное имя имеет смысл. На этом этапе мы, вероятно, хотели бы иметь хороший общий класс типов функторов, который бы находился между любыми двумя категориями. Может быть, что-то вроде:

class (Category catA, Category catB) => GFunctor f catA catB where
  gfmap :: catA a b -> catB (f a) (f b)

Вероятно, это уже существует где-то в библиотеке.

К сожалению, этот конкретный подход к определению различных функторов потребует дополнительных шумов newtype, поскольку (->) уже является категорией. На самом деле, собрать все типы должным образом будет непросто.

Так что, наверное, проще всего назвать это XFunctor или что-то в этом роде. Кроме того, только представьте себе каламбур!

РЕДАКТИРОВАТЬ: похоже, что categories предоставляет тип CFunctor, подобный этому , но немного умнее:

class (Category r, Category s) => CFunctor f r s | f r -> s, f s -> r where
  cmap :: r a b -> s (f a) (f b)

Однако я не уверен, что даже это достаточно общее! Я думаю, что мы могли бы также захотеть, чтобы он был более полиморфным по сравнению с видами.

person Tikhon Jelvis    schedule 06.06.2014
comment
Конечно, что-то вроде GFunctor существует; на самом деле математики будут рассматривать эндофункторы, подобные тем, что есть в Hask, как особый случай и обычно имеют дело с функторами между разными категориями. Эдвард параметризует class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where fmap :: r a b -> t (f a) (f b). - person leftaroundabout; 07.06.2014
comment
@leftaroundabout: Спасибо! Я нашел старую версию в category-extras, но похоже, что categories - это более новый и лучший пакет для использования. - person Tikhon Jelvis; 07.06.2014
comment
Я не понимаю, почему f и g должны быть функторами. Однако имеет смысл рассматривать x как функтор из одной категории общих экзистенциально количественно определенных морфизмов в другую категорию. Приятно видеть, что CFunctor существует, но жаль, что у него нет очень строгой и всеобъемлющей структуры, построенной вокруг него, чтобы быть полезным. Думаю, мне в любом случае придется специализироваться на моем варианте использования. Но этот ответ имеет смысл, так что я его приму! - person dflemstr; 07.06.2014
comment
Я на самом деле играю с воскрешением пакета categories здесь, в ZuriHac. - person Edward KMETT; 07.06.2014
comment
@dflemstr: f и g должны быть функторами, чтобы forall a. f a -> g a было естественным преобразованием, потому что именно так определяются естественные преобразования. Кроме того, наиболее простые типы такого рода являются функторами, и я думаю, что вам очень нужно fmap, чтобы делать что-нибудь полезное с Foo и Bar. - person Tikhon Jelvis; 07.06.2014

Bar f выглядит как Free Monad Free f ().

Тогда Foo - это do с одним или двумя <-. Может, и дальше дальше ...

person Franky    schedule 07.06.2014
comment
Как я уже сказал в вопросе, я просто придумал типы данных Foo и Bar. На самом деле я имею дело с очень разными структурами данных. - person dflemstr; 07.06.2014

Что бы это ни стоило, вы можете перефразировать упрощенную версию своего примера как

data Bar' r = Zero | Succ r
type Bar f = fix (Bar' . f)

Для каждой пары естественных преобразований eta1 :: f ~> g и eta2 :: Bar' ~> h мы получаем естественное преобразование (eta2 . eta1) :: (Bar' . f) ~> (h . g). И мы можем поднять это естественное преобразование над фиксированной точкой очевидным способом, чтобы получить fixed (eta2 . eta1) :: Bar f -> fix (h . g). Таким образом, ваш «чередующийся гомоморфизм» - это просто частный случай этой конструкции, когда у нас есть eta2 = id.

В целом это довольно стандартная конструкция (особенно для случаев, когда f - монада или комонада), хотя я не уверен, есть ли у нее конкретное широко признанное имя.

person wren romano    schedule 08.06.2014