2015-09-08 5 views
11

मैं GHC.TypeLits, और विशेष रूप से someNatVal को समझने की कोशिश कर रहा हूं। मैं जिस तरह से यह इस ब्लॉग post here में प्रयोग किया जाता है समझते हैं, लेकिन के रूप में उल्लेख एक ही उदाहरण, natVal का उपयोग कर की तरह लागू किया जा सकता था:जीएचसी में टाइप करें। टाइप करें कुछ नेटवल अच्छा है (जिसे हम नेटवेल के साथ पूरा नहीं कर सकते हैं)?

isLength :: forall len a. KnownNat len => Integer -> List len a -> Bool 
isLength n _ = n == natVal (Proxy :: Proxy len) 

वहाँ कि natVal साथ फिर से लिखा नहीं किया जा सकता someNatVal में से किसी का उपयोग करता है कर रहे हैं?

उत्तर

3

someNatVal का मुख्य उपयोग रन टाइम पर एक मान का उपयोग कर रहा है जैसे कि यह एक ऐसा प्रकार था जो संकलन समय पर ज्ञात नहीं था।

Can I have an unknown KnownNat? पर मेरा उत्तर वास्तव में गूंगा उदाहरण प्रदान करता है। एक प्रोग्राम लिखने के दस लाख बेहतर तरीके हैं जो वही काम करते हैं। लेकिन यह दिखाता है कि someNatVal करता है। यह अनिवार्य रूप से मूल्य से टाइप करने का एक कार्य है - उस प्रकार के दायरे को उस स्थान पर सीमित करने के अस्तित्व के साथ जहां यह स्थिर रूप से ज्ञात नहीं है।

+0

मुझे आपका उदाहरण, या यह दिखाने का इरादा नहीं है। क्या हो रहा है जो यहां नहीं हो रहा है: 'बी = बार "foo" :: बार बी में शो बी'? – jberryman

+0

@jberryman महत्वपूर्ण हिस्सा वह जगह है जहां से 'n' आता है। प्रकार 'एन' कैसे रन टाइम पर दिए गए मान से मेल खाता है? प्रकार केवल हास्केल में संकलन समय पर मौजूद हैं, आखिरकार। * वह * 'कुछ नेटवाल' करता है। – Carl

4

SomeNat existentially मात्रा निर्धारित किया जाता है:

data SomeNat = forall n. KnownNat n => SomeNat (Proxy n) 

जो SomeNat की तरह पढ़ता है, अच्छी तरह से, "कुछ n :: Nat"। Proxy एक सिंगलटन है जो टाइप सिस्टम को संतुष्ट करने के लिए टाइप-स्तर पर n को उठाने की अनुमति देता है - एक निर्भर रूप से टाइप की गई भाषा में हमें इस तरह के निर्माण की बहुत कम आवश्यकता होती है। हम और अधिक स्पष्ट रास्ता GADTs का उपयोग करने में SomeNat परिभाषित कर सकते हैं:

data SomeNat where 
    SomeNat :: forall n. KnownNat n => Proxy n -> SomeNat 

तो SomeNat एक Nat है, जो स्थिर नहीं जाना जाता है शामिल हैं।

फिर

someNatVal :: Integer -> Maybe SomeNat 

पढ़ता की तरह "someNatVal एक Integer और Maybe रिटर्न एक hiden Nat प्राप्त करता है"। हम KnownNat वापस नहीं कर सकते हैं, क्योंकि Known का अर्थ है "टाइप स्तर पर जाना जाता है", लेकिन टाइप स्तर पर मनमाने ढंग से Integer के बारे में कुछ भी नहीं है।

उलटा (सापेक्ष SomeNat आवरण और Proxy के बजाय एक proxy) someNatVal की

natVal :: forall n proxy. KnownNat n => proxy n -> Integer 

पढ़ता है की तरह "natVal कुछ है कि अपने प्रकार में एक Nat है प्राप्त करता है और उस NatInteger में बदल जाती है।"

रनटाइम मानों को लपेटने के लिए आमतौर पर मात्रात्मक डेटा प्रकार आमतौर पर used होते हैं। मान लें कि आप STDIN से Vec (सांख्यिकीय रूप से ज्ञात लंबाई वाली एक सूची) को पढ़ना चाहते हैं, लेकिन आप इनपुट की लंबाई की गणना कैसे करेंगे? अब कोई रास्ता नहीं है। तो आप एक सूची को लपेटते हैं, जिसे आपने पढ़ा है, इसी तरह के मात्रात्मक रूप से मात्रात्मक डेटा प्रकार में, इस प्रकार "मुझे लंबाई नहीं पता है, लेकिन एक मौजूद है"।

हालांकि यह कई मामलों में अधिक है। अस्तित्व में मात्रात्मक डेटा प्रकार के साथ कुछ करने के लिए आपको सामान्य होना आवश्यक है: उदा।यदि आपको SomeVec के तत्वों के योग को खोजने की आवश्यकता है तो आपको को Vec एस के लिए मनमाने ढंग से लंबाई के साथ परिभाषित करना होगा। फिर आप SomeVec को अनदेखा करते हैं और sumVec लागू करते हैं, इस प्रकार "मुझे एक लिपटे Vec की लंबाई नहीं पता है, लेकिन sumVec परवाह नहीं है"। लेकिन इस रैपिंग-अनैपिंग के बजाय आप directly सीपीएस का उपयोग कर सकते हैं।

हालांकि इस सामान्यता के कारण आपको ImpredicativeTypes को इस तरह की निरंतरताओं के साथ परिभाषित करने में सक्षम होने के लिए सक्षम करने की आवश्यकता होगी। उस स्थिति में अस्तित्व में क्वांटिफाइड डेटा वाली एक सूची common pattern है जो ImpredicativeTypes को प्राप्त करने की अनुमति देती है।

अपने उदाहरण के रूप में, के साथ ठीक से एक संस्करण है कि तुलना Nat रों lazier, एक संस्करण है कि तुलना Integer रों से परिभाषित Nat है,।

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