Поднятие изо в первый аргумент бифунктора
Control.Lens.Iso
содержит много замечательных функций для подъема Iso
в различные аргументы типа полезных абстракций. Например:
mapping
для произвольнойFunctor
scontramapping
заContravariant
функторыdimapping
,lmapping
а такжеrmapping
заProfunctor
sbimapping
заBifunctor
s
Я ищу функцию поднять 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