Объедините призмы, чтобы сосредоточиться на значении независимо от ветви - PullRequest
0 голосов
/ 15 января 2020

У меня есть суммарный тип возможных результатов, и в каждом результате есть определенный «Результат», на котором я хочу сосредоточиться. Я знаю, как получить этот «Результат» от каждого из результатов (для этого у меня есть куча призм), но я не знаю, как объединить эти призмы, чтобы я мог получить «Результат» из целого типа суммы, не волнуясь, в каком случае я нахожусь.

Упрощенный пример:

type OneAnother = Either Int Int

exampleOneAnother :: OneAnother
exampleOneAnother = Left 10

_one :: Prism' OneAnother Int
_one = _Left

_another :: Prism' OneAnother Int
_another = _Right

_result :: Lens' OneAnother Int
_result = ???
-- How can I combine _one and _another to get result regardless whether its left or right ?

Ответы [ 2 ]

1 голос
/ 29 января 2020

Как только призма фокусируется, она теряет контекст. Поэтому я не вижу способа определить _result в терминах _one и _another. Но вы, безусловно, можете добиться большего успеха, чем прибегнуть к unsafePartial:

import Data.Lens.Lens (Lens', lens)
import Data.Profunctor.Choice ((|||), (+++))

type OneAnother = Either Int Int

_result :: Lens' OneAnother Int
_result = lens getter setter
  where
  getter      = identity ||| identity
  setter e x  = (const x +++ const x) e

Украл это из репозитория profunctor-lens:

-- | Converts a lens into the form that `lens'` accepts.
lensStore :: forall s t a b . ALens s t a b -> s -> Tuple a (b -> t)
lensStore l = withLens l (lift2 Tuple)

Это не экспортируется как-то. С этой помощью следующее решение должно быть достаточно c:

import Prelude
import Control.Apply (lift2)
import Data.Lens.Common
import Data.Lens.Lens
import Data.Lens.Prism
import Data.Profunctor.Choice ((|||), (+++))
import Data.Tuple

_result :: Lens' OneAnother Int
_result = lens getter setter
  where
  getter      = identity ||| identity
  setter e x  = (const x +++ const x) e

lensStore :: forall s t a b . ALens s t a b -> s -> Tuple a (b -> t)
lensStore l = withLens l (lift2 Tuple)

data ABC
  = A Int
  | B (Tuple Boolean Int)
  | C OneAnother

lensABCInt :: Lens' ABC Int
lensABCInt = lens' case _ of
  A i -> map A <$> lensStore identity i
  B i -> map B <$> lensStore _2 i
  C i -> map C <$> lensStore _result i

Здесь ABC - ваш тип целевой суммы. Пока у каждого его варианта есть объектив, у вас есть объектив для него в целом.

0 голосов
/ 15 января 2020

Это лучшее, что у меня есть. Да, unsafePartial, явное сопоставление регистра ... Действительно надеюсь, что есть что-то лучшее.

_result :: Lens' OneAnother Int
_result = lens getter setter
  where
  getter :: OneAnother -> Int
  getter x@(Left _) = unsafePartial $ fromJust $ preview _one x

  getter x@(Right _) = unsafePartial $ fromJust $ preview _another x

  setter :: OneAnother -> Int -> OneAnother
  setter (Left _) x = review _one x

  setter (Right _) x = review _another x
...