2013-05-13 29 views
6

Tôi muốn tạo một hàm A -> Bool sử dụng một số ống kính của A. Ví dụ:Construct predicates với ống kính

data A = A { _foo :: Int, _bar :: Int } 
makeLenses ''A 

l :: [A] 

l' = filter (\a -> a^.foo > 100) l 

Các vị bộ lọc trông clumpsy bit. ((>100).(^.foo)) không tốt hơn nhiều. Nếu không có ống kính, tôi sẽ sử dụng ((>100) . foo).

Có cách nào tốt để tạo các vị từ như vậy với lens không? Lý tưởng nhất là nó cũng sẽ cho phép các vị từ như (\a -> a^.foo > 100 && a^.bar < 50).

Trả lời

4

Tôi nghĩ rằng ((>100).(^.foo)) có lẽ là tốt nhất bạn có thể làm chỉ bằng cách sử dụng toán tử chuẩn. Nếu bạn sẵn sàng để xác định toán tử so sánh mới cho ống kính, bạn có thể làm một cái gì đó như:

import Control.Lens hiding ((.>)) 
import Control.Monad  (liftM2) 
import Control.Monad.Reader (MonadReader) 
import Data.Function  (on) 

(.==) :: (MonadReader s m, Eq a) => Getting Bool s a -> a -> m Bool 
(.==) l = views l . (==) 
infix 4 .== 

(.==.) :: (MonadReader s m, Eq a) => Getting a s a -> Getting a s a -> m Bool 
(.==.) = liftM2 (==) `on` view 
infix 4 .==. 

(.<) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool 
(.<) l = views l . flip (<) 
infix 4 .< 

(.<.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool 
(.<.) = liftM2 (<) `on` view 
infix 4 .<. 

(.<=) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool 
(.<=) l = views l . flip (<=) 
infix 4 .<= 

(.<=.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool 
(.<=.) = liftM2 (<=) `on` view 
infix 4 .<=. 


(.>) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool 
(.>) l = views l . flip (>) 
infix 4 .> 

(.>.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool 
(.>.) = liftM2 (>) `on` view 
infix 4 .>. 

(.>=) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool 
(.>=) l = views l . flip (>=) 
infix 4 .>= 

(.>=.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool 
(.>=.) = liftM2 (>=) `on` view 
infix 4 .>=. 

(.&&.) :: Monad m => m Bool -> m Bool -> m Bool 
(.&&.) = liftM2 (&&) 
infix 3 .&&. 

(.||.) :: Monad m => m Bool -> m Bool -> m Bool 
(.||.) = liftM2 (||) 
infix 3 .||. 

Logic đằng sau những lựa chọn nhà điều hành là dấu chấm biểu thị phía có một ống kính, vì vậy bạn có thể viết hoặc foo .== 5 hoặc foo .==. bar (trong đó foobar là các ống kính). Thật không may, gói lens cũng định nghĩa toán tử (.<) của riêng mình, vì vậy có thể một số quy ước đặt tên khác sẽ tốt hơn. Đây chỉ là ý tưởng đầu tiên xuất hiện trong đầu tôi.

Sử dụng các nhà khai thác mới, bạn sẽ có thể viết những thứ như

l' = filter (foo .> 100 .&&. bar .< 50) l 
+0

này là rất tốt! Tôi tự hỏi nếu có someway để sử dụng các lớp học đa tham số loại để làm cho chỉ><= làm việc? –

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