Проблема с определением функции выбора для объектива profunctor - PullRequest
0 голосов
/ 23 октября 2018

Я возился с оптикой профессора, и у меня есть кое-что, с чем я не могу разобраться.

Кодирование объектива и его инверсия профессунером выглядит следующим образом:

type Optic p s t a b = p a b -> p s t

type Lens s t a b = forall p. Strong p => Optic p s t a b

type LensyReview t b = forall p. Costrong p => Optic p t t b b

Вы можете свободно конвертировать их между собой, используя

newtype Re p s t a b = Re { unRe :: p b a -> p t s }

instance Profunctor p => Profunctor (Re p s t) where
  dimap f g (Re p) = Re (p . dimap g f)

instance Strong p => Costrong (Re p s t) where
  unfirst  (Re p) = Re (p . first')
  unsecond (Re p) = Re (p . second')

instance Costrong p => Strong (Re p s t) where
  first'  (Re p) = Re (p . unfirst)
  second' (Re p) = Re (p . unsecond)

re :: Optic (Re p a b) s t a b -> Optic p b a t s
re optic = unRe (optic (Re id)))

. Теперь я попытался реализовать функцию выбора (https://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Lens.html#v:choosing) для объектива-проффунктора.

Оказываетсяиз-за того, что для этого требуется дополнительный класс типов:

class Profunctor p => SumProfunctor p where
  (+++!) :: p a b -> p a' b' -> p (Either a a') (Either b b')

, тогда, если мы включим SumProfunctor в Lens, мы можем написать

choosing :: Lens s t a b -> Lens s' t' a b -> Lens (Either s s') (Either t t') a b
choosing optic optic' = \pab -> optic pab +++! optic' pab

, но тогда должен быть другой класс "двойного" типа, которыйследует шаблону Re так, что

instance Unknown p => ProfunctorSum (Re p s t)
instance ProfunctorSum p => Unknown (Re p s t)

, так что объектив является обратимым.

Самое близкое, что я придумал, было:

class Profunctor p => Unknown p where
  unsum :: p (Either a a') (Either b b') -> (p a b -> r) -> (p a' b' -> r) -> r

, поскольку есть разумныйэкземпляр для Tagged of it, а затем вы можете написать

instance Unknown p => SumProfunctor (Re p s t) where
  Re f +++! Re g = Re (\s -> unsum s f g)

, но определить его в другом направлении, т.е.

instance SumProfunctor p => Unknown (Re p s t) where
  unsum = ???

не представляется возможным.

Amна правильном пути или нужен какой-то другой метод?

1 Ответ

0 голосов
/ 24 октября 2018

SumProfunctor эквивалентно Выбор , с p +++ q = left p . right q

Cochoice является двойным классом:

instance Cochoice p => Choice (Re p s t) where
    left' (Re f) = Re (f . unleft)
    right' (Re f) = Re (f . unright)

instance Choice p => Cochoice (Re p s t) where
    unleft (Re f) = Re (f . left')
    unright (Re f) = Re (f . right')
...