2016-11-14 11 views
5

fmap करने के लिए हास्केल की लेंस लाइब्रेरी का उपयोग करें नीचे दिए गए कोड में, मेरा प्रश्न शीर्ष-सबसे अधिक फ़ंक्शन someFunc से संबंधित है (नीचे सब कुछ सिर्फ एक पूर्ण उदाहरण प्रदान करने के लिए है)। मैं एक रिकॉर्ड-सिंटैक्स गेटर और fmap का उपयोग करता हूं। someFunc को लागू करने के लिए लेंस तरीका क्या है?लेंस

import   Control.Lens 
import   Data.IntMap (IntMap) 

someFunc :: Farm -> IntMap Size 
someFunc farm = 
    _barnSize <$> farm ^. farmBarns 

data Farm = Farm 
    { _farmBarns :: IntMap Barn 
    } 

farmBarns :: Lens' Farm (IntMap Barn) 
farmBarns = lens _farmBarns (\farm barns -> farm { _farmBarns = barns }) 

type Size = (Int, Int) 

data Barn = Barn 
    { _barnSize :: Size 
    } 

barnSize :: Lens' Barn Size 
barnSize = lens _barnSize (\barn size -> barn { _barnSize = size }) 

उत्तर

6

बस (^. barnSize) द्वारा _barnSize बदलने के लिए या, समतुल्य रूप, view barnSize:

someFunc :: Farm -> IntMap Size 
someFunc farm = view barnSize <$> farm ^. farmBarns 

एक "100% लेंस" समाधान के लिए, आप mapped सेटर उपयोग कर सकते हैं। इस मामले में, हालांकि, मुझे नहीं लगता कि ऐसा करने में कोई वास्तविक फायदा है।

someFunc :: Farm -> IntMap Size 
someFunc farm = (mapped %~ view barnSize) (farm ^. farmBarns) 

एक अन्य संभावित वर्तनी एक भी गेटर में सब कुछ गठबंधन करने के लिए to का उपयोग कर शामिल है। यह आपको यहां बहुत अधिक नहीं खरीदता है, लेकिन अगर आप लेंस शैली में अतिरिक्त गेटर्स/फोल्ड/इत्यादि को चुनकर शैली को रखना चाहते हैं तो यह कुछ हद तक सुविधाजनक हो सकता है।

someFunc :: Farm -> IntMap Size 
someFunc farm = farm ^. farmBarns . to (fmap (view barnSize)) 

एक विशेष उद्देश्य Combinator कि ऊपर to/(^.) संयोजन subsumes नहीं है। यह views कहा जाता है:

someFunc :: Farm -> IntMap Size 
someFunc farm = views farmBarns (fmap (view barnSize)) farm 
+0

आपका पहला सुझाव सरल और पठनीय है। –

+0

@ ruben.moor मैंने चौथी संभावना को जोड़ा, हालांकि मुझे नहीं लगता कि यह पहले की तुलना में बेहतर है। – duplode

2

आप mapped (या traversed) एक traversable से अधिक लेंस का उपयोग का उपयोग 'map' कर सकते हैं, आपके मामले में:

someFunc :: Farm -> IntMap Size 
someFunc farm = 
    farm ^. farmBarns & mapped %~ view barnSize 

इसमें कुछ समय भ्रमित हो सकता है, लेकिन यहाँ है क्या हो रहा है, मैं इसे एक छोटे से स्पष्ट

someFunc :: Farm -> IntMap Size 
someFunc farm = 
    (farm ^. farmBarns) & (mapped %~ (view barnSize)) 

तो मूल रूप से बनाने के लिए कोष्ठक जोड़ देंगे, हम farm ^. farmBarns का उपयोगपाने के लिए & के दाईं ओर खेत सेहम %~ का उपयोग कर एक सेटटर का निर्माण करते हैं जो over का इन्फिक्स है, हालांकि over फ़ंक्शन जो इसके लक्ष्य को पास करता है वास्तव में केवल लेंस का उपयोग करके बर्न आकार को केंद्रित करता है। view barnSize :: Barn -> Size

आखिरकार हम & का उपयोग सभी को एक साथ बांधने के लिए करते हैं जो flip $ के बराबर है और बाएं हाथ से सेटटर लेता है और बाएं हाथ के परिणाम पर इसका उपयोग करता है।

+0

'(^ ..) 'इस परिणाम को' IntMap आकार 'के बजाय' [आकार]' में बनाता है। – duplode

+0

आह, अच्छा पकड़ो! –

+0

मै मैप का उपयोग करने के लिए समाधान तय कर चुका हूं। –

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