2016-04-09 45 views

Odpowiedz

9

W ogólnym przypadku jest to niemożliwe. Prawdopodobnie najczęstszy przypadek, kiedy masz soczewki w różnych polach zapisu, soczewki są rozłączne, więc możesz zrobić obiektyw zgodny z prawem. Ale ogólnie to nie jest prawda. Dlatego kombinator nie jest dostarczany w bibliotekach, nawet gdyby był łatwy do napisania.

Załóżmy, że istnieje lensProd. To wystarczy, aby mieć taką samą soczewkę dwukrotnie:

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

badLens :: Lens' (a, b) (a, a) 
badLens = lensProd _1 _1 

Wtedy „Dostajesz to co można umieścić w” prawo nie trzymać. Powinno być:

view badLens (set badLens (1, 2) (3, 4)) ≡ (1, 2) 

Ale to nie może być prawdą, jak view badLens pair zwrotów jakąś wartość dwukrotnie: (x, x) dla wszystkich pair s.

@dfeuer podaje przykład jak zdefiniować lensProd.


Co ciekawe podwójny jest również zepsuty. W ogóle nie można mieć legalnego sumę pryzmat:

{-# 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 

Jak widać, kładziemy w Right, ale wydostać Left.

+0

Czy to naprawdę podwójny? – dfeuer

7

Jak wyjaśnił Phadej, nie ma sposobu, aby zrobić to ogólnie. Mimo to możesz to zrobić i ostrzec użytkowników, że powinni być ostrożni tylko po to, aby zastosować go do soczewek ortogonalnych.

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) 

Na przykład:

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) 
+2

Moglibyśmy uzyskać dowody rozłączności na poziomie typu, jak w kompachach, jakie sobie wyobrażam, i kombinator uwarunkowany dostarczeniem takiego dowodu – nicolas