2013-06-03 7 views
5

की एक खेल खेलते हैं। दो ढेर हैं जिनका उपयोग हम करने जा रहे हैं, दोनों काले/सफेद पक्षीय चिप्स शामिल हैं। ढेर बी में लेकिन यह कैसे -अपडेट कर रहा है कई उप क्षेत्रों

data Pile = Pile { _blacks, _whites :: Int } 
makeLenses ''Pile 

data Game = Game { _pileA, _pileB :: Pile } 
makeLenses ''Game 

वास्तव में एक चतुर चाल ढेर एक में एक काले रंग की चिप, और एक सफेद चिप से अधिक चालू करने के लिए हो सकता है?

cleverMove :: Game -> Game 
cleverMove game = game & pileA . blacks -~ 1 
         & pileA . whites +~ 1 
         & pileB . blacks +~ 1 
         & pileB . whites -~ 1 

बहुत सुंदर नहीं है। मैं प्रत्येक ढेर को दो बार संदर्भित किए बिना कैसे कर सकता हूं?

केवल एक चीज मैं के साथ आया था (और मुझे यह पसंद नहीं है):

cleverMove game = game & pileA %~ (blacks -~ 1) 
           . (whites +~ 1) 
         & pileB %~ (blacks +~ 1) 
           . (whites -~ 1) 

(माफ करना पहले से यह स्पष्ट है कि अगर - मैं थोड़े लेंस के लिए नया हूँ और मैं समुद्र में खो लग रहा है combinators और ऑपरेटरों lens पेशकश की। शायद वहाँ छिपा हर किसी की जरूरत के लिए सब कुछ है। ऐसा नहीं है कि यह, बुरा निश्चित रूप से है! लेकिन मैं चाहता हूँ वहाँ भी था एक पूरा मैनुअल शामिल थे।)

+2

आपको विकल्प 2 के बारे में क्या पसंद नहीं है? इससे उससे ज्यादा संक्षिप्त नहीं हो सकता है, है ना? – leftaroundabout

+0

@ बाएंराउंडबाउट मुझे यह पसंद नहीं है कि मुझे ब्रैकेट्स का उपयोग करना पड़ेगा, जो बहुमुखी अभिव्यक्तियों में शामिल होते हैं - जैसे कि 'डू' ब्लॉक और घोंसले के आगे के स्तर। – Artyom

+4

मुझे लगता है कि यह आपकी मदद करेगा यदि आपने कुछ आदर्श छद्म कोड दिखाया है जो आपके आदर्श वाक्यविन्यास जैसा दिखता है। –

उत्तर

5

एक TraversalLens जो "केंद्रित का सामान्यीकरण है "कई मूल्यों पर। traverse की तरह सोचें जो आपको Traversable tApplicative (traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b) में पहले से संशोधित मानों को Lens के प्रकार की तरह दिखता है, आपको नोटिस होगा-बस t b ~ whole) के बारे में सोचें।

एक Traversal के लिए हम सिर्फ मूल्यों हम बदलना चाहते हैं बंद चुन सकते हैं। उदाहरण के लिए, मुझे अपने Pile को थोड़ा सा सामान्यीकृत करने दें और Traversal बनाया।

data Pile = Pile { _blacks :: Int, _whites :: Int, _name :: String } deriving (Show) 
$(makeLenses ''Pile) 

counts :: Traversal' Pile Int 
counts f (Pile blacks whites name) = 
    Pile <$> f blacks <*> f whites <*> pure name 

इतनी के रूप में आप देख सकते हैं, मैं का दौरा दोनों blacks और f साथ whites लेकिन namepure छोड़ दें। यह लगभग उसी तरह आप एक Traversable उदाहरण लिखना छोड़कर आप हमेशा Traversable संरचना में निहित (समरूप) के सभी तत्वों पर जाएँ है।

Main*> Pile 0 0 "test" & counts +~ 1 
Pile {_blacks = 1, _whites = 1, _name = "test"} 

यह नहीं कि आप क्या चाहते करने के लिए पर्याप्त है, हालांकि, जब से तुम अलग मायनों में अपने क्षेत्रों अद्यतन करने की आवश्यकता है। इसके लिए, आपको अपना तर्क निर्दिष्ट करना होगा और यह सुनिश्चित करना होगा कि यह नियमों का एक पूरी तरह से अलग सेट बनाए रखे।

blackToWhite :: Pile -> Pile 
blackToWhite = (blacks -~ 1) . (whites +~ 1) 
संबंधित मुद्दे