如何制作两个镜头的产品?

pha*_*dej 7 haskell haskell-lens

如果我有两个镜头:

foo :: Lens' X Foo
bar :: Lens' X Bar
Run Code Online (Sandbox Code Playgroud)

有没有办法构建产品镜头:

foobar :: Lens' X (Foo, Bar)
foobar = ... foo bar 
Run Code Online (Sandbox Code Playgroud)

还是不可能?

pha*_*dej 9

一般情况下,这是不可能的.可能是最常见的情况,当你有镜头到不同的记录领域,镜头是不相交的,所以你可以制作一个合法的镜头.但总的来说,这不是真的.这就是为什么库中没有提供组合器的原因,即使它很容易编写.

假设lensProd存在.两次使用同一镜头就足够了:

_1 :: Lens' (a, b) a -- Simpler type

badLens :: Lens' (a, b) (a, a)
badLens = lensProd _1 _1
Run Code Online (Sandbox Code Playgroud)

然后,"你得到你放入的东西"法律不成立.它应该是:

view badLens (set badLens (1, 2) (3, 4)) ? (1, 2)
Run Code Online (Sandbox Code Playgroud)

但它不可能是真的,因为view badLens pair两次返回一些值:(x, x)对于所有的pairs.

@dfeuer给出了如何定义的示例lensProd.


有趣的是,双重也被打破了.一般来说,你不能有合法的棱镜总和:

{-# LANGUAGE RankNTypes #-}

import Control.Applicative
import Control.Lens

-- |
-- >>> :t sumPrism _Just _Nothing :: Prism' (Maybe a) (Either a ())
-- sumPrism _Just _Nothing :: Prism' (Maybe a) (Either a ())
--  :: (Applicative f, Choice p) =>
--     p (Either a ()) (f (Either a ())) -> p (Maybe a) (f (Maybe a))
--
sumPrism :: Prism' a b -> Prism' a c -> Prism' a (Either b c)
sumPrism ab ac = prism' build match where
    build (Left b)  = ab # b
    build (Right c) = ac # c

    match x = Left <$> x ^? ab <|> Right <$>  x ^? ac

-- The law
--
-- @
-- preview l (review l b) ? Just b
-- @
--
-- breaks with
--
-- >>> preview badPrism (review badPrism (Right 'x'))
-- Just (Left 'x')
-- 
badPrism :: Prism' a (Either a a)
badPrism = sumPrism id id
Run Code Online (Sandbox Code Playgroud)

如你所见,我们投入了Right,但是出去了Left.


dfe*_*uer 7

正如phadej所解释的那样,一般来说,没有守法的方法.但是,无论如何你都可以这样做,并警告你的用户,他们最好只注意将它应用于正交镜头.

import Control.Lens
import Control.Arrow ((&&&))

fakeIt :: Lens' s x -> Lens' s y -> Lens' s (x,y)
fakeIt l1 l2 =
  lens (view l1 &&& view l2)
       (\s (x,y) -> set l1 x . set l2 y $ s)
Run Code Online (Sandbox Code Playgroud)

例如:

Prelude Control.Lens A> set (fake _1 _2) (7,8) (1,2,3)
(7,8,3)
Prelude Control.Lens A> view (fake _1 _2) (1,2,3)
(1,2)
Run Code Online (Sandbox Code Playgroud)

  • 我们可以在我想象的compdata中得到一个类型级别的不相交证明,并且组合器以提供这样的证明为条件 (2认同)