मेरी डाटामूल्य फ़ील्ड को किसी फ़ील्ड को सीमित करने के लिए कैसे करें?
data User = User { uRank :: Int, uProgress :: Int }
में मैं मान [-1, 1, 3], उदाहरण के लिए की एक सूची के लिए uRank
सीमित करना चाहते हैं।
मैं यह कैसे कर सकता हूं?
मेरी डाटामूल्य फ़ील्ड को किसी फ़ील्ड को सीमित करने के लिए कैसे करें?
data User = User { uRank :: Int, uProgress :: Int }
में मैं मान [-1, 1, 3], उदाहरण के लिए की एक सूची के लिए uRank
सीमित करना चाहते हैं।
मैं यह कैसे कर सकता हूं?
एक छोटे से योग प्रकार को परिभाषित करना इस विशिष्ट प्रश्न का सबसे अच्छा जवाब है। आप इस प्रभाव को प्राप्त करने के लिए स्मार्ट कन्स्ट्रक्टर के साथ newtype
का भी उपयोग कर सकते हैं।
newtype Rank = UnsafeMkRank { unRank :: Int }
mkRank :: Int -> Maybe Rank
mkRank i
| i `elem` [-1, 1, 3] = Just (UnsafeMkRank i)
| otherwise = Nothing
अब, आप केवल सुरक्षित mkRank
निर्माता का उपयोग प्रदान की है, तो आप मान सकते हैं कि आपके Rank
मूल्यों Int
मूल्यों आप चाहते हैं।
स्मार्ट कन्स्ट्रक्टर अक्सर मॉड्यूल निर्यात सूचियों के संयोजन के साथ प्रयोग किया जाता है: मॉड्यूल MyMod (रैंक, myRank) जहां .. कन्स्ट्रक्टर UnsafeMkRank निर्यात नहीं करेगा, आपको अन्य मॉड्यूल में इसका उपयोग करने से मना कर देगा, अगर आप (या अन्य उपयोगकर्ता) कभी भी अच्छी रैंक बनाने के लिए भूल जाओ। –
कुछ के लिए इतना छोटा है, तो आप एक सटीक प्रकार को परिभाषित करना चाहिए:
data Rank = RankNegOne | RankOne | RankThree -- There are probably better names
data User = User { uRank :: Rank, uProgress :: Int }
हास्केल पूर्णांकों का एक सबसेट के रूप में सब कुछ सांकेतिक शब्दों में बदलना करने के लिए आप के लिए मजबूर नहीं करता है; इस का लाभ ले!
बड़े सबसेट्स के लिए जहां यह अनावश्यक होगा, आप आश्रित प्रकार की तलाश कर रहे हैं, जो (हाल ही में?) सीधे हास्केल द्वारा समर्थित नहीं है।
क्या यहां उपयोग में निर्भर प्रकार का त्वरित उदाहरण दिखाना संभव है? वास्तव में रैंक मूल्य के लिए बहुत सारे मूल्य हैं। – osager
यह संभव है, लेकिन मैं नहीं हूं :) मैं अस्पष्ट होने से अपनी अज्ञानता को घुमाने का प्रयास कर रहा था। – chepner
यह ठीक है। कम से कम यह एक अच्छा सूचक है। मैं थोड़ा गहरा – osager
तरल हास्केल, जो हास्केल के शीर्ष पर परिष्करण प्रकार जोड़ता है, ऐसा कर सकता है। ट्यूटोरियल here के सही खंड को देखें।
सबसे पहले आप अपने डेटा प्रकार को सामान्य के रूप में परिभाषित करते हैं।
module User where
data User = User { uRank :: Int
, uProgress :: Int
}
अगला हम आपके प्रतिबंध को परिष्करण प्रकार के रूप में परिभाषित करते हैं। तरल हास्केल उपयोगकर्ता वाक्यविन्यास {[email protected] blah @-}
के साथ एनोटेशन टिप्पणी करते हैं। हम -1, 1, 3
RestrictedInt
प्रकार के साथ पहले की अपनी अजीब प्रतिबंध को परिभाषित करेंगे:
{[email protected] type RestrictedInt = {v : Int | v == -1 || v == 1 || v == 3} @-}
है, RestrictedInt
एक Int
वह यह है कि या तो -1
, 1
, या 3
है। ध्यान दें कि आप आसानी से श्रेणियां और अन्य प्रतिबंध लिख सकते हैं, इसे वैध मूल्यों के बारे में कुछ दिमागी गणना नहीं होनी चाहिए।
हम अब फिर से परिभाषित इस प्रतिबंधित पूर्णांक प्रकार का उपयोग हमारे शोधन भाषा में अपने डेटा प्रकार:
{[email protected] data User = User { uRank :: RestrictedInt
, uProgress :: Int }
@-}
यह अपनी परिभाषा के लिए, लेकिन सिर्फ Int
के बजाय प्रतिबंध प्रकार के साथ इसी तरह की है। हम एक प्रकार के उपनाम रखने के बजाय प्रतिबंध को रेखांकित कर सकते थे लेकिन फिर आपके User
डेटा प्रकार बहुत अपठनीय होगा।
आप अच्छे संस्कार परिभाषित कर सकते हैं और liquid
उपकरण शिकायत नहीं होगा:
goodValue :: User
goodValue = User 1 12
लेकिन बुरी मूल्यों एक त्रुटि में परिणाम: या
badValue :: User
badValue = User 10 12
$ liquid so.hs
(अपने संपादक के एकीकरण, अगर आपको लगता है कि है सेटअप) उत्पन्न करता है:
**** RESULT: UNSAFE ************************************************************
so.hs:16:12-18: Error: Liquid Type Mismatch
16 | badValue = User 10 12
^^^^^^^
Inferred type
VV : {VV : GHC.Types.Int | VV == ?a}
not a subtype of Required type
VV : {VV : GHC.Types.Int | VV == (-1)
|| (VV == 1
|| VV == 3)}
In Context
?a := {?a : GHC.Types.Int | ?a == (10 : int)}
क्या यह एक ऐसा नहीं है जो आप enu के साथ कर सकते हैं मी और एक फ़ंक्शन का उपयोग करें जो इसे इट्स पर मैप करता है यदि आप उन पर अंकगणित करना चाहते हैं? –