2016-04-09 14 views

Trả lời

9

Trong trường hợp chung, điều này là không thể. Có lẽ trường hợp phổ biến nhất khi bạn có ống kính đến các trường khác nhau của bản ghi, các ống kính rời nhau, vì vậy bạn có thể tạo ra một ống kính hợp pháp. Nhưng nói chung nó không đúng. Đây là lý do tại sao các combinator không được cung cấp trong các thư viện, thậm chí nó sẽ dễ dàng để viết.

Giả sử lensProd tồn tại. Đủ để lấy cùng một ống kính hai lần:

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

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

Sau đó, luật "Bạn lấy lại những gì bạn đưa vào" không giữ. Nó nên là:

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

Nhưng nó không thể là sự thật, như view badLens pair lợi nhuận một số giá trị gấp đôi: (x, x) cho tất cả pair s.

@dfeuer cung cấp ví dụ về cách xác định lensProd.


Điều thú vị là đôi cũng bị hỏng. Nói chung bạn không thể có số tiền hợp pháp của lăng kính:

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

Như bạn có thể thấy, chúng tôi đưa vào Right, nhưng nhận ra Left.

+0

Đó là thực sự kép? – dfeuer

7

Như phadej giải thích, không có cách tuân thủ pháp luật nào để làm điều này nói chung. Tuy nhiên, bạn có thể làm điều đó anyway và cảnh báo người dùng của bạn rằng họ nên cẩn thận hơn chỉ áp dụng nó cho ống kính trực giao.

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) 

Ví dụ:

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

Chúng tôi có thể nhận được một loại bằng chứng về sự phân tách như trong compdata tôi tưởng tượng, và một combinator có điều kiện khi cung cấp bằng chứng như vậy – nicolas

Các vấn đề liên quan