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)
但是,它需要一个有点烦人的类型签名.
这个组合器可能无法实现.考虑:
> (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)
这两者显然是不同的.当两个镜头"重叠"时出现问题,并且这不是在类型中编码的.
我刚刚偶然发现了这个实际的函数,因为它是在lens(在模块名称中带有关于不健全的注释:)中Control.Lens.Unsound定义的
-- | 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\nRun Code Online (Sandbox Code Playgroud)\n