Поднятие изо в первый аргумент бифунктора

Control.Lens.Iso содержит много замечательных функций для подъема Isoв различные аргументы типа полезных абстракций. Например:

  • mapping для произвольной Functors
  • contramapping за Contravariant функторы
  • dimapping, lmapping а также rmapping за Profunctors
  • bimapping за Bifunctors

Я ищу функцию поднять Iso в first аргумент Bifunctor, но, похоже, его там нет. В настоящее время я определяю это так:

firsting
  :: Bifunctor f
  => AnIso s t a b
  -> Iso (f s x) (f t y) (f a x) (f b y)
firsting p = bimapping p (iso id id)

Эта функция уже существует где-то или bimapping p (iso id id) Лучше не бывает?

1 ответ

Решение

Обновить

Благодаря вашему вопросу, следующая версия Control.Lens.Iso будет включать firsting а также seconding,


iso id id выглядит немного некрасиво Давайте попробуем разобрать это на части.

type Iso s t a b =
  forall f p . (Functor f, Profunctor p) =>
                               p a (f b) -> p s (f t)

--plain :: Iso s t s t
--plain = iso id id

plain :: (Functor f, Profunctor p) => p s (f t) -> p s (f t)
plain = id

Таким образом, вы можете сократить вашу реализацию до

firsting p = bimapping p id

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

Включая определение bimapping

bimapping :: (Bifunctor f, Bifunctor g) => AnIso s t a b -> AnIso s' t' a' b' -> Iso (f s s') (g t t') (f a a') (g b b')
bimapping f g = withIso f $ \ sa bt -> withIso g $ \s'a' b't' ->
  iso (bimap sa s'a') (bimap bt b't')

и упрощение использования first, ты получаешь

firsting p = withIso p $ \ sa bt ->
             iso (first sa) (first bt)

Это особенно ясное выражение, я думаю. Оно использует withIso сломать p в две функции, которые составляют изоморфизм, использует first поднять каждый из них, чтобы применить к первому аргументу бифунктора, а затем упаковать их обратно с iso, Если соответствующий бифунктор имеет оптимизированный first это делает что-то лучше, чем можно сделать с bimap, то это также будет быстрее, чем реализация, использующая bimapping,

Встраивание iso дает

firsting p = withIso p $ \ sa bt ->
             dimap (first sa) (fmap (first bt))

Наконец, встраивание withIso (копаться в Control.Lens.Internal.Isoчто мы, вероятно, не должны делать),

firsting p =
  case p (Exchange id Identity) of
    Exchange sa bt ->
      dimap (first sa) (fmap (first (runIdentity #. bt)))

Кстати, подпись типа для plainбез избыточного контекста

plain :: p s (f t) -> p s (f t)

Это точно так же как

plain :: Equality s t s t
Другие вопросы по тегам