组合棱镜以关注一个值而不考虑分支

Combine prisms to focus on a value regardless of a branch

我有一个可能结果的总和类型,在每个结果中都有一个我想关注的"Result"。我知道如何从每个结果中得到 "Result"(为此我有一堆棱镜),但我不知道如何组合这些棱镜以便我可以从中获取 "Result"整个 sumtype,不用担心我在哪种情况下。

简化示例:

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 ?

这是迄今为止我得到的最好的。是的,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

一旦棱镜聚焦,它就会失去上下文。所以我看不到根据 _one_another 定义 _result 的方法。但是你当然可以比诉诸 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)

它没有以某种方式导出。在这种帮助下,以下解决方案应该足够通用:

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 是您的目标总和类型。只要它的每个变体都有一个镜头,您就拥有了一个整体的镜头。