2017-03-14 14 views
6
import Control.Lens 
import Control.Lens.TH 

data Foo = Foo { 
    _bar, _baz :: Int 
    } 
makeLenses ''Foo 

अब अगर मैं संशोधित करना चाहते हैं दोनों क्षेत्रों int, मैंक्या एकाधिक रिकॉर्ड फ़ील्ड के लिए एक सेटटर में सेटर्स को गठबंधन करने का कोई सीधा तरीका है?

barbaz :: Setter' Foo Int 
barbaz = sets $ \foo f -> foo & bar %~ f 
           & baz %~ f 

कर सकते हैं, लेकिन यह यह करने के लिए एक बहुत बदसूरत मैनुअल तरीका की तरह लगता है।

क्या इसे सीधे लेंस/तीर संयोजकों के साथ प्राप्त किया जा सकता है?

+0

ऐसा लगता है कि यह आपके प्रश्न का उत्तर देता है: http://stackoverflow.com/questions/17528119/combining-lenses – Shersh

+0

क्या आप 'फू' के बजाय एक टुपल का उपयोग कर रहे थे, तो आप कुछ ऐसा कर सकते थे ['(1,2) और दोनों। ~ 10'] (https://hackage.haskell.org/package/lens-4.15.1/docs/Control-Lens-Traversal.html#v:both) tuple के दोनों तत्वों को '10' पर सेट करने के लिए। – Alec

उत्तर

1

मैंने पहले इस समस्या थी और एक समाधान है कि उन्हें एक Traversal में संयोजन से दो लेंस के लिए काम करता है है:

fields2 :: Lens' s a -> Lens' s a -> Traversal' s a 
fields2 f1 f2 f s = (\v1 v2 -> s & f1 .~ v1 & f2 .~ v2) <$> f (s ^. f1) <*> f (s ^. f2) 

barbaz = fields2 bar baz 

इस से की तरह इस्तेमाल किया जा सकता है:

foo & barbaz %~ f 

यह एक है थोड़ा गंदे और स्केल नहीं करता है लेकिन यह मेरे लिए काम करता है: डी अगर कोई अच्छा जवाब पोस्ट करता है तो मैं बहुत खुश रहूंगा!

2

लेंस उस के लिए तैयार किए गए संयोजक नहीं है, संभवतः बीक्यूज आप अवैध सेटर्स (या लेंस) प्राप्त कर सकते हैं यदि घटकों का ध्यान ओवरलैप हो।

data Trio a = Trio a a a 
    deriving (Show) 

oneTwo :: Setter' (Trio a) (a, a) 
oneTwo = sets $ \f (Trio x y z) -> let (x', y') = f (x, y) in Trio x' y' z 

twoThree :: Setter' (Trio a) (a, a) 
twoThree = sets $ \f (Trio x y z) -> let (y', z') = f (y, z) in Trio x y' z' 

cheating :: Setter' (Trio a) (a, a) 
cheating = sets $ \f x -> x & oneTwo %~ f & twoThree %~ f 
GHCi> Trio 1 1 1 & cheating %~ bimap (2*) (2*) & cheating %~ bimap (3+) (3+) 
Trio 5 10 5 
GHCi> Trio 1 1 1 & cheating %~ (bimap (2*) (2*) <&> bimap (3+) (3+)) 
Trio 5 13 5 

आपके मामले में, (के रूप में आप and Cristoph Hegemann कर रहे हैं) हाथ से सेटर/ट्रेवर्सल के निर्माण के लिए सबसे अच्छा विकल्प के रूप में bennofs से कहीं और सुझाव दिया (लिंक के लिए धन्यवाद Shersh, liftA2 (>=>) :: ASetter' s a -> ASetter' s a -> ASetter' s a हो रहा है)। आप (कुछ अन्य Bitraversable या) एक सजातीय जोड़ी के लिए एक लेंस के आसपास झूठ बोल रही है करने के लिए है, तो आप both साथ इसे से बाहर ट्रेवर्सल प्राप्त कर सकते हैं:

data Foo = Foo 
    { _bar, _baz :: Int 
    } deriving (Show) 
makeLenses ''Foo 

barBaz :: Iso' Foo (Int, Int) 
barBaz = iso ((,) <$> view bar <*> view baz) (Foo <$> fst <*> snd) 
GHCi> Foo 1 2 & barBaz . both %~ (2*) 
Foo {_bar = 2, _baz = 4} 

फिर भी एक और संभावना के लिए Data.Data.Lens का शोषण कर रहा है

{-# LANGUAGE DeriveDataTypeable #-} 

import Control.Lens 
import Data.Data.Lens 
import Data.Data 

data Foo = Foo 
    { _bar, _baz :: Int 
    } deriving (Show, Data, Typeable) 
makeLenses ''Foo 

barBaz :: Traversal' Foo Int 
barBaz = template 
GHCi> Foo 1 2 & barBaz %~ (2*) 
Foo {_bar = 2, _baz = 4} 
: एक खास प्रकार के सभी क्षेत्रों का एक ट्रेवर्सल मिल
संबंधित मुद्दे

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