बाकी क्षेत्रों की नकल करते हुए, एक रिकॉर्ड में एकल फ़ील्ड असाइन करने का शॉर्टहैंड तरीका?


119

मान लीजिए कि मेरे पास निम्नलिखित रिकॉर्ड है ADT:

data Foo = Bar { a :: Integer, b :: String, c :: String }

मैं एक ऐसा कार्य चाहता हूं जो एक रिकॉर्ड ले और एक रिकॉर्ड (उसी प्रकार का) लौटाए जहां सभी क्षेत्रों में समान मानों को तर्क के रूप में पारित किया गया हो, जैसे:

walkDuck x = Bar { a = a x, b = b x, c = lemonadeStand (a x) (b x) }

उपरोक्त काम करता है, लेकिन अधिक फ़ील्ड्स (कहना 10) के साथ एक रिकॉर्ड के लिए , इस तरह के फ़ंक्शन को बनाने से बहुत अधिक टाइपिंग होती है जो मुझे लगता है कि काफी अनावश्यक है।

क्या ऐसा करने के कोई कम थकाऊ तरीके हैं?


3
अपडेट के लिए रिकॉर्ड सिंटैक्स मौजूद है, लेकिन जल्दी ही बोझिल हो जाता है। इसके बजाय लेंस पर एक नज़र डालें ।
कैट प्लस प्लस

जवाबों:


155

हां, रिकॉर्ड फ़ील्ड अपडेट करने का एक अच्छा तरीका है। GHCi में आप कर सकते हैं -

> data Foo = Foo { a :: Int, b :: Int, c :: String }  -- define a Foo
> let foo = Foo { a = 1, b = 2, c = "Hello" }         -- create a Foo
> let updateFoo x = x { c = "Goodbye" }               -- function to update Foos
> updateFoo foo                                       -- update the Foo
Foo {a = 1, b = 2, c = "Goodbye" }

9
RecordWildCardsविस्तार के रूप में अच्छी तरह से अच्छा, एक दायरे में "खोल" क्षेत्रों के लिए हो सकता है। अद्यतनों के लिए हालांकि यह बहुत अच्छा नहीं है:incrementA x@Foo{..} = x { a = succ a }
जॉन पूर्डी

2
BTW, फ्रीज में (जेवीएम के लिए एक हास्केल) आप फ़ंक्शन को updateFoo x = x.{ c = "Goodbye" }( .ऑपरेटर को नोट करें ) के रूप में परिभाषित करेंगे ।
0dB

वैसे अच्छा वीडियो youtube.com/watch?v=YScIPA8RbVE
Damián राफेल Lattenero

धन्यवाद। अफसोस की बात है कि मुझे कोई हास्केल लिखे हुए एक लंबा समय हो गया!
क्रिस टेलर

37

यह लेंस के लिए एक अच्छा काम है :

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"

फिर:

setL c "Goodbye" test

आपके स्ट्रिंग के लिए फ़ील्ड 'c' को अपडेट करेगा।


5
और लेंस-जैसे पैकेज अक्सर फ़ील्ड प्राप्त करने और सेट करने के कार्यों के अलावा ऑपरेटरों को परिभाषित करते हैं। उदाहरण के लिए, test $ c .~ "Goodbye"यह है कि यह कैसे lensहोगा। मैं यह नहीं कह रहा हूं कि यह सहज है, लेकिन एक बार जब आप ऑपरेटरों को जानते हैं तो मुझे उम्मीद है कि यह आसानी से आ जाएगा $
थॉमस एम। डुबिसन

3
क्या आप जानते हैं कि setL कहाँ गया है? मैं Control.Lens इंपोर्ट कर रहा हूं , लेकिन ghc रिपोर्ट कर रहा है कि setL अपरिभाषित है।
dbanas

1
सेट के बजाय सेट का उपयोग करें
सुबोध I

16

आपको सहायक कार्यों को परिभाषित करने या लेंस को नियोजित करने की आवश्यकता नहीं है। स्टैंडर्ड हास्केल में पहले से ही आपकी जरूरत है। आइए डॉन स्टीवर्ट का उदाहरण लेते हैं:

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"

तब आप केवल test { c = "Goodbye" }अद्यतन रिकॉर्ड प्राप्त करने के लिए कह सकते हैं ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.