Что это за комбинатор объективов?

Делаю комбинатор линз на Ruby и не могу сообразить, какое у него общепринятое название. Неизвестная функция объединяет две линзы с одинаковым типом источника и типа цели (используя Benjamin C. . Терминология Пирса) — это хэш-карта. Неизвестная функция принимает эти две линзы и возвращает новую линзу с тем же типом источника и типом цели, что и исходные линзы.

Это выглядит так (синтаксис Ruby):

lens_a.get(source)
> {:title => "some title"}
lens_b.get(source)
> {:description => "some description"}
new_lens = unknown_function(lens_a, lens_b)
new_lens.get(source)
> {:title => "some title", :description => "some description"}

Схему комбинатора, который я пытаюсь построить, можно увидеть на слайде 18 этой презентации (название слайда "Объединить?").

Я просмотрел документы по линзам от Haskell ( небольшие части которых я могу понять), но я не могу понять, что это за комбинатор.

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


person bmaddy    schedule 04.04.2014    source источник
comment
Есть ли причина, по которой вы используете библиотеку объективов 1.2 вместо 4.1.2?   -  person bheklilr    schedule 04.04.2014
comment
Я делаю это в Руби. Я не знаю Хаскель. Я просто смотрю туда как ссылку. Я посмотрю документы 4.1.2 - спасибо за подсказку.   -  person bmaddy    schedule 04.04.2014
comment
Я не смог найти ничего особенного в библиотеке объективов (как мне показалось, странного), но я думаю, что что-то вроде zipLenses или merge подойдет. В Haskell это может выглядеть примерно так: merge :: Lens' s a -> Lens' s b -> Getter s (a, b); merge l1 l2 = to (\x -> (view l1 x, view l2 x)). Очевидно, что это не будет работать как Setter, так что это не может быть полноценным Lens.   -  person bheklilr    schedule 04.04.2014
comment
Из любопытства, у вас есть ссылка на код вашей рубиновой линзы? Мне было бы интересно его использовать!   -  person Chris    schedule 14.06.2014
comment
Да, прямо сейчас он встроен в другой проект. Код, который вас, вероятно, заинтересует, находится здесь . Если вы найдете что-то из этого полезного, дайте мне знать, и я могу превратить его в драгоценный камень. Кроме того, дайте мне знать, если у вас есть какие-либо вопросы по этому поводу, я буду рад помочь прояснить ситуацию.   -  person bmaddy    schedule 15.06.2014


Ответы (2)


Я считаю, что примерно правильная идея для вашего комбинатора в Haskell такова:

merge :: Lens' s t -> Lens' s t -> Lens' s (t, t)

возможно обобщается на

merge :: Lens' s t -> Lens' s t' -> Lens' s (t, t')

так что ваши две цели могут различаться по типу. Мы могли бы «реализовать» это следующим образом, но это обнаружит проблему.

merge l1 l2 = lens pull push where
  pull s          = (view l1 s, view l2 s)
  push s (t1, t2) = set l2 t2 (set l1 t1 s)

В частности, в части Setter этого уравнения мы явно упорядочиваем способ, которым возвращаем наши значения. Это означает, что мы можем использовать merge для создания линз, которые нарушают законы линз. В частности, они нарушают закон PUT-GET. Вот контрпример

newtype Only a = Only a

-- A lens focused on the only slot in Only
only :: Lens' (Only a) a
only inj (Only a) = Only <$> inj a

-- We merge this lens with *itself*
testLens :: Lens' (Only a) (a, a)
testLens = merge only only

-- and now it violates the lens laws
> view testLens (Only 1 & testLens .~ (1,2))
(2,2)

Или, проще говоря, если мы merge соединим линзу с самой собой, то сторона Setter превратится в два последовательных множества в одном и том же месте. Это означает, что если мы попытаемся установить его с парой различных значений, сохранится только второй набор, и, таким образом, мы нарушим закон PUT-GET.

Библиотека lens старается избегать недопустимых объективов, поэтому этот комбинатор недоступен. Самое близкое, что у нас есть, это alongside< /a>, который имеет следующий (ограниченный) тип

alongside :: Lens'  s     a
          -> Lens'  s'    a'
          -> Lens' (s,s') (a,a')

но, как вы можете видеть, это гарантирует, что наш источник также является типом продукта, так что Setter применяются однозначно к каждой стороне источника. Если бы мы попытались написать dup Lens, который мы могли бы скомпоновать с alongside для сборки merge, мы столкнемся с той же проблемой, что и раньше.

dup  :: Lens' a (a, a) -- there are two possible implementations, neither are lenses
dup1 inj a = fst <$> inj a
dup2 inj a = snd <$> inj a

Теперь все это может быть довольно техническим и бессмысленным с точки зрения Ruby. В Ruby у вас не будет навязываемой компилятором безопасности типов, поэтому вы, скорее всего, смешаете множество правил вместе и добьетесь меньшей строгости. В таком случае может иметь смысл реализовать merge с его семантикой последовательной записи.

На самом деле, основываясь на приведенных вами примерах, похоже, что контрпример, на который я указал, не может даже произойти в Ruby, поскольку ваш целевой тип является хэшем и уже обеспечивает уникальные ключи.

Но важно отметить, что merge можно использовать для создания неподходящих линз, если вы посмотрите на это достаточно внимательно. По сути, это означает, что в более сложных сценариях использование merge может легко привести к странным ошибкам, вызванным нарушением нашего интуитивного понимания того, что такое объектив. Это может не быть большой проблемой для Ruby, поскольку сложная абстракция в любом случае осуждается в сообществе Ruby, но именно поэтому у нас есть законы.

person J. Abrahamson    schedule 04.04.2014
comment
Это был замечательный ответ - спасибо, что нашли время, чтобы объяснить это так ясно. Мне особенно понравилась часть на простом английском языке, так как Haskell все еще довольно чужд для меня (однако мой интерес растет). - person bmaddy; 04.04.2014

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

Что-то типа:

compoundEye :: Traversable tl => tl (Lens s t a b) -> Traversal s t a b

Но результаты поиска не обещают.

person Boyd Stephen Smith Jr.    schedule 04.04.2014