Haskell Language
रिकॉर्ड सिंटैक्स
खोज…
बेसिक सिंटेक्स
रिकॉर्ड राशि बीजीय data
प्रकार का एक विस्तार है जो फ़ील्ड को नाम देने की अनुमति देता है:
data StandardType = StandardType String Int Bool --standard way to create a sum type
data RecordType = RecordType { -- the same sum type with record syntax
aString :: String
, aNumber :: Int
, isTrue :: Bool
}
फ़ील्ड नाम का उपयोग रिकॉर्ड से बाहर नामित फ़ील्ड प्राप्त करने के लिए किया जा सकता है
> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> :t r
r :: RecordType
> :t aString
aString :: RecordType -> String
> aString r
"Foobar"
रिकॉर्ड्स को पैटर्न के खिलाफ मैच किया जा सकता है
case r of
RecordType{aNumber = x, aString=str} -> ... -- x = 42, str = "Foobar"
ध्यान दें कि सभी क्षेत्रों का नाम नहीं होना चाहिए
रिकॉर्ड्स उनके खेतों का नामकरण करके बनाए जाते हैं, लेकिन उन्हें साधारण योग प्रकारों के रूप में भी बनाया जा सकता है (अक्सर उपयोगी होता है जब खेतों की संख्या छोटी होती है और बदलने की संभावना नहीं होती है)
r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
r' = RecordType "Foobar" 42 True
यदि एक नामित क्षेत्र के बिना एक रिकॉर्ड बनाया जाता है, तो संकलक एक चेतावनी जारी करेगा, और परिणामस्वरूप मूल्य undefined
होगा।
> let r = RecordType {aString = "Foobar", aNumber= 42}
<interactive>:1:9: Warning:
Fields of RecordType not initialized: isTrue
> isTrue r
Error 'undefined'
किसी रिकॉर्ड का कोई क्षेत्र उसके मान को सेट करके अद्यतन किया जा सकता है। असमय खेत नहीं बदलते।
> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> let r' = r{aNumber=117}
-- r'{aString = "Foobar", aNumber= 117, isTrue = True}
जटिल रिकॉर्ड प्रकारों के लिए लेंस बनाने के लिए अक्सर उपयोगी होता है।
फील्ड वैल्यू में बदलाव करते हुए रिकॉर्ड की नकल करना
मान लीजिए कि आपके पास यह प्रकार है:
data Person = Person { name :: String, age:: Int } deriving (Show, Eq)
और दो मूल्य:
alex = Person { name = "Alex", age = 21 }
jenny = Person { name = "Jenny", age = 36 }
alex
से कॉपी करके टाइप Person
का एक नया मूल्य बनाया जा सकता है, यह निर्दिष्ट करने के लिए कि कौन से मान बदलते हैं:
anotherAlex = alex { age = 31 }
अब alex
और anotherAlex
मूल्य होंगे:
Person {name = "Alex", age = 21}
Person {name = "Alex", age = 31}
न्यूटाइप के साथ रिकॉर्ड
रिकॉर्ड सिंटैक्स का उपयोग newtype
साथ प्रतिबंध के साथ किया जा सकता है कि बिल्कुल एक क्षेत्र के साथ एक कंस्ट्रक्टर है। यहाँ लाभ यह है कि फंक्शन का ऑटोमैटिक क्रिएशन है, जो न्यूटाइप को अनचेक करने के लिए है। इन क्षेत्रों को अक्सर मोनड्स के लिए run
के साथ शुरू करने के लिए नामित किया जाता है, मोनोइड्स के लिए get
है, और अन्य प्रकारों के लिए un
।
newtype State s a = State { runState :: s -> (s, a) }
newtype Product a = Product { getProduct :: a }
newtype Fancy = Fancy { unfancy :: String }
-- a fancy string that wants to avoid concatenation with ordinary strings
यह ध्यान रखना महत्वपूर्ण है कि रिकॉर्ड सिंटैक्स का उपयोग आमतौर पर मूल्यों को बनाने के लिए कभी नहीं किया जाता है और फ़ील्ड का नाम सख्ती से अलिखित के लिए उपयोग किया जाता है
getProduct $ mconcat [Product 7, Product 9, Product 12]
-- > 756
RecordWildCards
{-# LANGUAGE RecordWildCards #-}
data Client = Client { firstName :: String
, lastName :: String
, clientID :: String
} deriving (Show)
printClientName :: Client -> IO ()
printClientName Client{..} = do
putStrLn firstName
putStrLn lastName
putStrLn clientID
पैटर्न Client{..}
कंस्ट्रक्टर Client
सभी क्षेत्रों को दायरे में लाता है, और पैटर्न के बराबर है
Client{ firstName = firstName, lastName = lastName, clientID = clientID }
इसे अन्य फील्ड मैचर्स के साथ भी जोड़ा जा सकता है:
Client { firstName = "Joe", .. }
इसके बराबर है
Client{ firstName = "Joe", lastName = lastName, clientID = clientID }
फ़ील्ड लेबल के साथ डेटा प्रकार को परिभाषित करना
फ़ील्ड लेबल के साथ डेटा प्रकार को परिभाषित करना संभव है।
data Person = Person { age :: Int, name :: String }
यह परिभाषा सामान्य रिकॉर्ड परिभाषा से भिन्न होती है क्योंकि यह * रिकॉर्ड एक्सेसर्स को भी परिभाषित करती है जिसका उपयोग डेटा प्रकार के भागों तक पहुंचने के लिए किया जा सकता है।
इस उदाहरण में, दो रिकॉर्ड एक्सेसर्स को परिभाषित किया गया है, age
और name
, जो हमें क्रमशः age
और name
फ़ील्ड तक पहुंचने की अनुमति देते हैं।
age :: Person -> Int
name :: Person -> String
रिकॉर्ड एक्सेसर्स सिर्फ हास्केल फ़ंक्शन हैं जो कंपाइलर द्वारा स्वचालित रूप से उत्पन्न होते हैं। जैसे, उनका उपयोग साधारण हास्केल कार्यों की तरह किया जाता है।
खेतों का नामकरण करके, हम अपने कोड को अधिक पठनीय बनाने के लिए कई अन्य संदर्भों में फ़ील्ड लेबल का भी उपयोग कर सकते हैं।
पैटर्न मिलान
lowerCaseName :: Person -> String
lowerCaseName (Person { name = x }) = map toLower x
हम संबंधित फ़ील्ड लेबल की स्थिति में स्थित मूल्य को एक नए मूल्य (इस मामले में x
) से मेल खाते हुए पैटर्न से बांध सकते हैं जिसका उपयोग किसी परिभाषा के RHS पर किया जा सकता है।
NamedFieldPuns
साथ पैटर्न मिलान
lowerCaseName :: Person -> String
lowerCaseName (Person { name }) = map toLower name
इसके बजाय NamedFieldPuns
एक्सटेंशन हमें केवल उस फ़ील्ड लेबल को निर्दिष्ट करने की अनुमति देता है जिसे हम मिलान करना चाहते हैं, यह नाम तब परिभाषा के RHS पर छाया हुआ है, इसलिए name
संदर्भ देते हुए रिकॉर्ड एक्सेसर के बजाय मान को संदर्भित करता है।
RecordWildcards
साथ पैटर्न मिलान
lowerCaseName :: Person -> String
lowerCaseName (Person { .. }) = map toLower name
RecordWildCards
का उपयोग करके मिलान करते RecordWildCards
, सभी फ़ील्ड लेबल को दायरे में लाया जाता है। (इस विशिष्ट उदाहरण में, name
और age
)
यह विस्तार थोड़ा विवादास्पद है क्योंकि यह स्पष्ट नहीं है कि मूल्यों को दायरे में कैसे लाया जाता है यदि आप Person
की परिभाषा के बारे में सुनिश्चित नहीं हैं।
रिकॉर्ड अद्यतन
setName :: String -> Person -> Person
setName newName person = person { name = newName }
फ़ील्ड लेबल के साथ डेटा प्रकारों को अपडेट करने के लिए विशेष सिंटैक्स भी है।