如何在"平行"中组合镜头

mb1*_*b14 7 haskell haskell-lens

我是新手Control.Lens,我正在尝试将2个镜头组合成"并行"(不是顺序),就像我对`Control.Arrow.&&&)一样.

如果我从lens文档中提取示例:

`data Foo a = Foo { _baz :: Int, _bar :: Int, a }
Run Code Online (Sandbox Code Playgroud)

我希望能够做到这样的事情:

>> let foo = (bar &&& baz) .~ (1, 20) $ Foo undefined undefined "FOO"
>> foo ^. (bar &&& baz) 
(1, 20)
Run Code Online (Sandbox Code Playgroud)

我到处寻找,我找不到办法.那是因为:

  • (&&&)与另一个名字存在,我错过了它.
  • 这毫无用处.我不应该需要它,因此没有人费心去实施它.
  • 以另一种方式做(使用both<*>)是微不足道的

更新

&&& 可以这样实现:

(/|\) :: Lens' f a -> Lens' f b -> Lens' f (a, b)
a /|\ b = lens getBoth setBoth where
    getBoth f = (f ^. a, f ^. b)
    setBoth f (v, w) = a .~ v $ f' where
        f' = b .~ w $ f

barz :: Lens' Foo (Int, Int)
barz = bar /|\ baz
Run Code Online (Sandbox Code Playgroud)

但是,它需要一个有点烦人的类型签名.

ben*_*ofs 7

这个组合器可能无法实现.考虑:

> (baz &&& baz) .~ (1,5)
Run Code Online (Sandbox Code Playgroud)

这应该怎么办?

即使是组合子的弱点:

(/|\) :: Lens' s a -> Lens' s a -> Traversal' s a
a /|\ b = (a &&& b) . both
Run Code Online (Sandbox Code Playgroud)

会打破法律:

例如,让我们来看看baz /|\ baz.既然a Traversal也是a Setter,它也必须满足Setter法律.现在,采取第二个二传法:

over (baz /|\ baz) (f . g) = over (baz /|\ baz) f . over (baz /|\ baz) g
Run Code Online (Sandbox Code Playgroud)

现在,我们得到:

over (baz /|\ baz) (f . g) 
= \(Foo _baz _bar) -> Foo (f . g . f . g $ _baz) _bar
Run Code Online (Sandbox Code Playgroud)

和:

over (baz /|\ baz) f . over (baz /|\ baz) g
= \(Foo _baz _bar) -> Foo (f . f . g . g $ _baz) _bar
Run Code Online (Sandbox Code Playgroud)

这两者显然是不同的.当两个镜头"重叠"时出现问题,并且这不是在类型中编码的.

  • @bennofs:是的,一个&&& a`打破了镜头法则,但它是如何相关的?`bar &&& baz`没有,这才是最重要的.我可以找到参数(a,b),以便"镜头ab"打破镜头定律.这并不能阻止`镜头`功能成为有效功能.此外,`&&&`可以实现,似乎工作(见更新) (5认同)

lef*_*out 3

我刚刚偶然发现了这个实际的函数,因为它是在lens(在模块名称中带有关于不健全的注释:)中Control.Lens.Unsound定义的

\n\n
-- | A lens product. There is no law-abiding way to do this in general.\n-- Result is only a valid \'Lens\' if the input lenses project disjoint parts of \n-- the structure @s@. Otherwise "you get what you put in" law\n--\n-- @\n-- \'Control.Lens.Getter.view\' l (\'Control.Lens.Setter.set\' l v s) \xe2\x89\xa1 v\n-- @\n--\n-- is violated by\n--\n-- >>> let badLens :: Lens\' (Int, Char) (Int, Int); badLens = lensProduct _1 _1\n-- >>> view badLens (set badLens (1,2) (3,\'x\'))\n-- (2,2)\n--\n-- but we should get @(1,2)@.\n--\n-- Are you looking for \'Control.Lens.Lens.alongside\'?\n--\nlensProduct :: ALens\' s a -> ALens\' s b -> Lens\' s (a, b)\nlensProduct l1 l2 f s =\n    f (s ^# l1, s ^# l2) <&> \\(a, b) -> s & l1 #~ a & l2 #~ b\n
Run Code Online (Sandbox Code Playgroud)\n