2013-06-17 9 views
19

इन आयात होने के साथ नक्शे से एक से अधिक परिणाम प्राप्त करना:"लेंस"

> import Control.Lens 
Control.Lens> import qualified Data.Map as Map 

और के रूप में परिभाषित एक नक्शे के मूल्य इस प्रकार है:

Control.Lens Map> let m = Map.fromList [('a', 1), ('c', 3), ('b', 2)] 

मैं बहुत की तरह एक के बाद यह तत्व एक है प्राप्त कर सकते हैं:

Control.Lens Map> view (at 'b') m 
Just 2 

क्या मैं जानना चाहता हूँ इस जैसे चाबियों का एक सेट है, है:

Control.Lens Map> import qualified Data.Set as Set 
Control.Lens Map Set> let keys = Set.fromList ['d', 'c', 'b'] 

कैसे, इस तरह के एक गेटर (मुझे लगता है) के निर्माण के लिए उपयोग कर रहा है जो मुझे मिलान तत्वों का एक सेट (या एक सूची) प्राप्त करने के लिए सक्षम हो जाएगा:

Control.Lens Map Set> view (**???**) m 
[3, 2] 

सूचना परिणाम होता है कि केवल 2 तत्व, क्योंकि कुंजी 'd' के लिए कोई मिलान नहीं है।

उत्तर

21

निम्नलिखित यदि आप केवल एक से अधिक फ़ील्ड पर एक गेटर चाहते काम करेंगे यहाँ सब newtype shenanigans के साथ सही Monoid उदाहरण है।

सबसे पहले, आप monoid का एक उदाहरण (कि उदाहरण HEAD में में है, लेकिन अभी तकपहले से ही lens >= 4 में परिभाषित नहीं जारी किया लेंस से Accessor बनाने के लिए है, तो आप केवल अगर आप उदाहरण परिभाषित करने की जरूरत की जरूरत है पुस्तकालय के पुराने संस्करण के साथ काम करना)।

import Data.Monoid 
import Control.Lens 

instance Monoid r => Monoid (Accessor r a) where 
    mempty = Accessor mempty 
    mappend (Accessor a) (Accessor b) = Accessor $ a <> b 

इसके बाद आप एक एकल ट्रेवर्सल में एकाधिक लेंस/traversals गठबंधन करने के लिए है कि उदाहरण का उपयोग कर सकते हैं:

>>> import qualified Data.Set as S 
>>> import qualified Data.Map as M 
>>> import Data.Foldable (foldMap) 
>>> import Control.Lens 
>>> let m = M.fromList [('a',1), ('b',2), ('c',3)] 
>>> let k = S.fromList ['b','c','e'] 
>>> m ^.. foldMap at k 
[Just 2,Just 3,Nothing] 
>>> m ^.. foldMap ix k 
[2,3] 

foldMap Accessor और कार्यों के लिए monoid उदाहरण के लिए monoid उदाहरण का उपयोग करता है।

+2

इस उत्तर को स्वीकार करें। यह मेरी तुलना में काफी बेहतर है। –

+0

बढ़िया! मुझे लगा कि इसे सरल होना था। धन्यवाद! –

5

मुझे लगता है कि यह समाधान है:

import Control.Applicative 
import Control.Lens 
import qualified Data.Map as M 
import Data.Monoid hiding ((<>)) 

empty :: (Applicative f, Monoid a) => (b -> f b) -> (a -> f a) 
empty _ _ = pure mempty 

(<>) 
    :: (Applicative f, Monoid a) 
    => ((b -> f b) -> (a -> f a)) 
    -> ((b -> f b) -> (a -> f a)) 
    -> ((b -> f b) -> (a -> f a)) 
(l1 <> l2) f a = mappend <$> (l1 f a) <*> (l2 f a) 

उदाहरण:

>>> toListOf (at "A" <> at "B" <> at "C") (M.fromList [("A", 1), ("B", 2)]) 
[Just 1, Just 2, Nothing] 

विचार है कि एक Traversal एक monoid है। सही समाधान के लिए Traversal को नया टाइप करने की आवश्यकता होगी।

संपादित करें:

import Control.Applicative 
import Control.Lens 
import qualified Data.Map as M 
import Data.Monoid 
import Data.Foldable 

newtype Combinable f a b = Combinable { useAll :: (b -> f b) -> (a -> f a) } 

instance (Applicative f, Monoid a) => Monoid (Combinable f a b) where 
    mempty = Combinable (\_ _ -> pure mempty) 
    mappend (Combinable l1) (Combinable l2) 
     = Combinable (\f a -> mappend <$> (l1 f a) <*> (l2 f a)) 

myMap :: M.Map String Int 
myMap = M.fromList [("A", 1), ("B", 2)] 

myLens :: Traversal' (M.Map String Int) (Maybe Int) 
myLens = useAll $ foldMap (Combinable . at) ["A", "B", "C"] 

उदाहरण::

>>> toListOf myLens myMap 
[Just 1,Just 2, Nothing] 
+0

धन्यवाद! दूसरा समाधान बहुत करीब है। क्या 'myLens' के किसी भी अपडेट का कोई मौका है, जो' toListOf myLens myMap' को उचित सूची से बाहर कर देगा, जैसा कि 'catMaybes $ toListOf myLens myMap' वर्तमान में करेगा? –

+0

@ निकितावोल्कोव मुझे ऐसा लगता है। इसे काम करने की कोशिश करने के लिए मुझे एक सेकंड दें। –

संबंधित मुद्दे