लेंस, फेकैबल्स, डेटा-एक्सेसर - स्ट्रक्चर एक्सेस और म्यूटेशन के लिए कौन सी लाइब्रेरी बेहतर है


173

अभिलेखों के क्षेत्रों तक पहुँचने और हेरफेर करने के लिए कम से कम तीन लोकप्रिय पुस्तकालय हैं। जिन्हें मैं जानता हूं वे हैं: डेटा-एक्सेसर, फेकैबल्स और लेंस।

व्यक्तिगत रूप से मैंने डेटा-एक्सेसर के साथ शुरुआत की और अब मैं उनका उपयोग कर रहा हूं। हालाँकि हाल ही में हैस्केल-कैफ़े पर फेकैबल्स के श्रेष्ठ होने की एक राय थी।

इसलिए मैं उन तीनों (और शायद अधिक) पुस्तकालयों की तुलना में दिलचस्पी रखता हूं।


3
आज तक, lensपैकेज में सबसे अमीर कार्यक्षमता और प्रलेखन है, इसलिए यदि आप इसकी जटिलता और निर्भरता पर ध्यान नहीं देते हैं, तो यह जाने का तरीका है।
मॉड्यूलर

जवाबों:


200

कम से कम 4 पुस्तकालय हैं जिन्हें मैं लेंस प्रदान करने से अवगत हूं।

एक लेंस की धारणा यह है कि यह कुछ आइसोमॉर्फिक प्रदान करता है

data Lens a b = Lens (a -> b) (b -> a -> a)

दो कार्य प्रदान करना: एक गेटटर, और एक सेटर

get (Lens g _) = g
put (Lens _ s) = s

तीन कानूनों के अधीन:

सबसे पहले, अगर आप कुछ डालते हैं, तो आप इसे वापस निकाल सकते हैं

get l (put l b a) = b 

दूसरा जो मिलना और फिर सेट करना उत्तर नहीं बदलता है

put l (get l a) a = a

और तीसरा, दो बार डालना एक बार डालने के समान है, या यों कहें कि दूसरा डाल जीतता है।

put l b1 (put l b2 a) = put l b1 a

ध्यान दें, कि आपके लिए इन कानूनों की जाँच करने के लिए टाइप सिस्टम पर्याप्त नहीं है, इसलिए आपको यह सुनिश्चित करने की आवश्यकता है कि आप चाहे जो भी लेंस का उपयोग करें।

इन पुस्तकालयों में से कई शीर्ष पर अतिरिक्त कॉम्बिनेटरों का एक समूह भी प्रदान करते हैं, और आमतौर पर टेम्पलेट हैस्केल मशीनरी के कुछ प्रकार सरल रिकॉर्ड प्रकारों के क्षेत्रों के लिए स्वचालित रूप से लेंस उत्पन्न करते हैं।

इसे ध्यान में रखते हुए, हम विभिन्न कार्यान्वयनों की ओर रुख कर सकते हैं:

क्रियान्वयन

fclabels

fclabels शायद लेंस पुस्तकालयों के बारे में सबसे आसानी से तर्क दिया गया है, क्योंकि इसका a :-> bसीधे उपरोक्त प्रकार से अनुवाद किया जा सकता है। यह के लिए एक श्रेणी उदाहरण प्रदान करता है(:->) जिसके लिए यह उपयोगी है क्योंकि यह आपको लेंस की रचना करने की अनुमति देता है। यह एक अराजक Pointप्रकार भी प्रदान करता है जो यहां इस्तेमाल किए गए लेंस की धारणा को सामान्य करता है, और आइसोमोर्फिज्म से निपटने के लिए कुछ प्लंबिंग करता है।

गोद लेने में एक बाधा यह fclabelsहै कि मुख्य पैकेज में टेम्पलेट-हैसेल पाइपलाइन शामिल है, इसलिए पैकेज हस्केल 98 नहीं है, और इसके लिए (काफी गैर-विवादास्पद) भी आवश्यकता होती हैTypeOperators एक्सटेंशन की ।

डेटा-एक्सेसर

[संपादित करें: data-accessorअब इस प्रतिनिधित्व का उपयोग नहीं कर रहा है, लेकिन इसके समान एक रूप में स्थानांतरित हो गया हैdata-lens । मैं इस टिप्पणी को रख रहा हूं, हालांकि।]

डेटा-एक्सेसरfclabels भाग की तुलना में कुछ अधिक लोकप्रिय है , क्योंकि यह है हास्केल 98. हालांकि, आंतरिक प्रतिनिधित्व के अपनी पसंद मुझे मेरे मुंह में एक छोटा सा ऊपर फेंक बनाता है।

Tलेंस का प्रतिनिधित्व करने के लिए यह जिस प्रकार का उपयोग करता है उसे आंतरिक रूप से परिभाषित किया गया है

newtype T r a = Cons { decons :: a -> r -> (a, r) }

नतीजतन, getलेंस के मूल्य के लिए, आपको 'a' तर्क के लिए अपरिभाषित मान जमा करना होगा! यह मुझे एक अविश्वसनीय रूप से बदसूरत और तदर्थ कार्यान्वयन के रूप में प्रभावित करता है।

उस ने कहा, हेनिंग ने एक अलग ' डेटा-एक्सेसर-टेम्प्लेट ' पैकेज में आपके लिए एक्सेसर्स को स्वचालित रूप से उत्पन्न करने के लिए टेम्प्लेट-हैस्केल प्लंबिंग को शामिल किया है ।

यह एक बड़े पैमाने पर संकुल का लाभ है जो पहले से ही इसे नियोजित करता है, हास्केल 98, और सर्व-महत्वपूर्ण प्रदान करता है Category उदाहरण , इसलिए यदि आप इस बात पर ध्यान नहीं देते हैं कि सॉसेज कैसे बनाया जाता है, तो यह पैकेज वास्तव में बहुत ही उचित विकल्प है ।

लेंस

इसके बाद, लेंस पैकेज होता है, जो देखता है कि एक लेंस दो राज्य मठों के बीच एक राज्य मोनड होमोमोर्फिज्म प्रदान कर सकता है, लेंस को सीधे ऐसे मोनड होमोमोर्फिज्म के रूप में परिभाषित करता है।

अगर यह वास्तव में अपने लेंस के लिए एक प्रकार प्रदान करने के लिए परेशान है, तो उनके पास रैंक -2 प्रकार होगा:

newtype Lens s t = Lens (forall a. State t a -> State s a)

नतीजतन, मुझे यह दृष्टिकोण पसंद नहीं है, क्योंकि यह बेवजह आपको हास्केल 98 से बाहर कर देता है (यदि आप सार में अपने लेंस को प्रदान करने के लिए एक प्रकार चाहते हैं) और आपको Categoryलेंस के लिए उदाहरण से वंचित करता है , जो आपको देगा। उनके साथ रचना करें .। कार्यान्वयन के लिए बहु-पैरामीटर प्रकार की कक्षाओं की आवश्यकता होती है।

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

इसके अलावा, शुरुआत में बताई गई साइड-कंडीशन की वास्तव में इस रूप में अच्छी अभिव्यक्ति नहीं है। 'Fclabels' के रूप में यह सीधे मुख्य पैकेज में रिकॉर्ड प्रकार के लिए लेंस उत्पन्न करने के लिए टेम्पलेट-हैस्केल विधि प्रदान करता है।

Categoryउदाहरण की कमी के कारण , मुख्य पैकेज में बारोक एन्कोडिंग और टेम्पलेट-हैस्केल की आवश्यकता है, यह मेरा पसंदीदा पसंदीदा कार्यान्वयन है।

डेटा लेंस

[संपादित करें: 1.8.0 तक, ये कोमोनॉड-ट्रांसफॉर्मर पैकेज से डेटा-लेंस में चले गए हैं]

मेरा data-lensपैकेज स्टोर कोमोनड के संदर्भ में लेंस प्रदान करता है ।

newtype Lens a b = Lens (a -> Store b a)

कहाँ पे

data Store b a = Store (b -> a) b

विस्तारित यह इसके बराबर है

newtype Lens a b = Lens (a -> (b, b -> a))

आप इसे पुनः प्राप्त करने वाले के रूप में देख सकते हैं कि गेटर और सेटर से आम तर्क को जोड़ा जाता है, जिसमें तत्व को पुनः प्राप्त करने के परिणाम के साथ एक जोड़ी होती है, और एक नया मान वापस लाने के लिए एक सेटर। यह कम्प्यूटेशनल लाभ प्रदान करता है कि 'सेटर'। यहाँ मूल्य को प्राप्त करने के लिए उपयोग किए जाने वाले कुछ कार्यों को पुन: चक्रित किया जा सकता है, जिससे fclabelsपरिभाषा की तुलना में अधिक कुशल 'संशोधित' संचालन के लिए , विशेषकर जब एक्सेसरों को जंजीर में बांध दिया जाता है।

इस प्रतिनिधित्व के लिए एक अच्छा सैद्धांतिक औचित्य भी है, क्योंकि 'लेंस' मूल्यों का सबसेट जो इस प्रतिक्रिया की शुरुआत में बताए गए 3 कानूनों को संतुष्ट करता है, ठीक वे लेंस हैं जिनके लिए लिपटे फ़ंक्शन स्टोर कोमोनड के लिए एक 'कोमोनॉड कोलजेब्रा' है। । यह एक लेंस के लिए 3 बालों वाले कानूनों lको 2 अच्छे पॉइंटफ्री समकक्षों में बदल देता है:

extract . l = id
duplicate . l = fmap l . l

यह दृष्टिकोण पहले उल्लेख किया और रसेल ओ'कॉनर के में वर्णित किया गया Functorहै Lensके रूप में Applicativeकरने के लिए है Biplate: पेश Multiplate किया गया था और एक प्रीप्रिंट के आधार पर के बारे में ब्लॉग जेरेमी गिबन्स द्वारा।

इसमें लेंस के साथ कड़ाई से काम करने के लिए कई प्रकार के कॉम्बिनेटर और कंटेनर के लिए कुछ स्टॉक लेंस भी शामिल हैं, जैसे कि Data.Map

तो लेंस data-lensएक Category( lensesपैकेज के विपरीत ) के रूप में, हास्केल 98 ( fclabels/ के विपरीत lenses) हैं, साने हैं (पीछे के अंत के विपरीत data-accessor) और थोड़ा अधिक कुशल कार्यान्वयन data-lens-fdप्रदान करते हैं , बाहर कदम रखने के इच्छुक लोगों के लिए मोनास्टस्टेट के साथ काम करने की कार्यक्षमता प्रदान करते हैं। हास्केल 98, और टेम्पलेट-हैस्केल मशीनरी अब उपलब्ध है data-lens-template

अद्यतन 6/28/2012: अन्य लेंस कार्यान्वयन रणनीतियाँ

आइसोमोर्फिज्म लेंस

दो अन्य लेंस एनकोडिंग हैं जो विचार करने लायक हैं। पहले एक लेंस को क्षेत्र के मूल्य में एक संरचना को तोड़ने के तरीके के रूप में देखने के लिए एक अच्छा सैद्धांतिक तरीका देता है, और 'बाकी सब कुछ'।

समरूपता के लिए एक प्रकार को देखते हुए

data Iso a b = Iso { hither :: a -> b, yon :: b -> a }

ऐसे वैध सदस्य संतुष्ट हों hither . yon = id, औरyon . hither = id

हम एक लेंस का प्रतिनिधित्व कर सकते हैं:

data Lens a b = forall c. Lens (Iso a (b,c))

ये मुख्य रूप से लेंस के अर्थ के बारे में सोचने के तरीके के रूप में उपयोगी हैं, और हम अन्य लेंस को समझाने के लिए एक तर्क उपकरण के रूप में उपयोग कर सकते हैं।

वैन लाहरोवेन लेंस

हम लेंस मॉडल कर सकते हैं ऐसी है कि वे साथ हो सकती हैं (.)और idयहां तक कि एक के बिना Categoryउपयोग कर उदाहरण

type Lens a b = forall f. Functor f => (b -> f b) -> a -> f a

हमारे लेंस के प्रकार के रूप में।

फिर एक लेंस को परिभाषित करना उतना ही आसान है:

_2 f (a,b) = (,) a <$> f b

और आप स्वयं के लिए यह सत्यापित कर सकते हैं कि फ़ंक्शन रचना लेंस संरचना है।

मैंने हाल ही में लिखा है कि आप लेंस परिवारों को प्राप्त करने के लिए वैन लाहरोवेन लेंस को और कैसे सामान्य कर सकते हैं जो कि उनके हस्ताक्षर को सामान्य करके, खेतों के प्रकारों को बदल सकते हैं

type LensFamily a b c d = forall f. Functor f => (c -> f d) -> a -> f b

इसका दुर्भाग्यपूर्ण परिणाम यह है कि लेंस के बारे में बात करने का सबसे अच्छा तरीका रैंक 2 बहुरूपता का उपयोग करना है, लेकिन लेंस को परिभाषित करते समय आपको सीधे उस हस्ताक्षर का उपयोग करने की आवश्यकता नहीं है।

Lensमैं के लिए ऊपर परिभाषित _2वास्तव में एक है LensFamily

_2 :: Functor f => (a -> f b) -> (c,a) -> f (c, b)

मैंने एक पुस्तकालय लिखा है जिसमें लेंस, लेंस परिवार और गेटर्स, सेटरर्स, फोल्ड्स और ट्रैवर्सल्स सहित अन्य सामान्यीकरण शामिल हैं। यह lensपैकेज के रूप में हैकेज पर उपलब्ध है ।

फिर से, इस दृष्टिकोण का एक बड़ा फायदा यह है कि लाइब्रेरी मेंटेनर वास्तव में आपकी लाइब्रेरी में इस शैली में लेंस बना सकते हैं, बिना किसी लेंस लाइब्रेरी निर्भरता के बिना, केवल Functor f => (b -> f b) -> a -> f aविशेष प्रकार के 'ए' और 'बी' के लिए कार्यों की आपूर्ति करके । यह गोद लेने की लागत को बहुत कम करता है।

चूंकि आपको नए लेंस को परिभाषित करने के लिए वास्तव में पैकेज का उपयोग करने की आवश्यकता नहीं है, इसलिए लाइब्रेरी हस्केल 98 को रखने के बारे में मेरी पहले की चिंताओं से बहुत दबाव पड़ता है।


28
मुझे इसके आशावादी दृष्टिकोण के लिए फैकलबेल्स पसंद हैं:->
Tener


10
क्या हास्केल 1998 संगत महत्वपूर्ण है? क्योंकि यह संकलक विकास को आसान बनाता है? और क्या हमें इसके बजाय हास्केल 2010 के बारे में बात करना चाहिए?
येरचू

55
अरे नहीं! मैं इसका मूल लेखक था data-accessor, और फिर मैंने इसे हेनिंग को सौंप दिया और ध्यान देना बंद कर दिया। a -> r -> (a,r)प्रतिनिधित्व भी मुझे परेशान करता है, और अपने मूल कार्यान्वयन सिर्फ अपने तरह था Lensप्रकार। Heeennnninngg !!
लूकी

5
Yairchu: यह ज्यादातर इसलिए है कि आपके पुस्तकालय में ghc के अलावा एक संकलक के साथ काम करने का मौका हो सकता है। किसी और के पास टेम्पलेट हास्केल नहीं है। 2010 यहाँ कुछ भी प्रासंगिक नहीं जोड़ता है।
एडवर्ड KMETT
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.