2010-02-18 5 views
9

यह काम करता है:यह हास्केल कठोर प्रकार त्रुटि कैसे बनाता है?

data Wrapped a = Wrapped a 

alpha :: IO s -> IO() 
alpha x = do 
    rv <- wrapit x 
    return() 
    where  
     wrapit :: IO s -> IO (Wrapped s) 
     wrapit x' = do 
      a <- x' 
      return (Wrapped a) 

यह नहीं करता है:

data Wrapped a = Wrapped a 

alpha :: IO s -> IO() 
alpha x = do 
    rv <- wrapit 
    return() 
    where  
     wrapit :: IO (Wrapped s) 
     wrapit = do 
      a <- x 
      return (Wrapped a) 

क्यों?

उत्तर

19

यह इस प्रकार है कि किस प्रकार के चर मानक हैं और मानक हास्केल में मात्राबद्ध हैं। तुम इतनी तरह दूसरे संस्करण काम कर सकते हैं:

{-# LANGUAGE RankNTypes, ScopedTypeVariables #-} 

module RigidProblem where 

data Wrapped a = Wrapped a 

alpha :: forall s. IO s -> IO()             
alpha x = do 
    rv <- wrapit 
    return() 
    where  
     wrapit :: IO (Wrapped s) 
     wrapit = do 
      a <- x 
      return (Wrapped a) 

दो परिवर्तन किए गए हैं: RankNTypes और ScopedTypeVariables भाषा एक्सटेंशन सक्षम रहे हैं और स्पष्ट forall salpha के प्रकार के हस्ताक्षर में जोड़ा जाता है। दो एक्सटेंशन में से पहला यह है कि हमें स्पष्ट forall s को alpha के शरीर के दायरे में दायरे में लाने की अनुमति देता है, जबकि दूसरा यह बनाता है कि wrapit पर हस्ताक्षर प्रकार अनुमान इंजन से अंतर्निहित नहीं है forall s - इसके बजाय, उस हस्ताक्षर में s को एक प्रकार परिवर्तनीय नाम दिया जाता है जो दायरे में होना चाहिए और इसके साथ पहचाना जाना चाहिए।

हास्केल में वर्तमान डिफ़ॉल्ट स्थिति, अगर मैं सही ढंग से समझ, बस इतना ही कठोर प्रकार चर (जिसका अर्थ है प्रकार हस्ताक्षर स्पष्ट रूप से प्रोग्रामर द्वारा प्रदान में होने वाली प्रकार चर) परोक्ष मात्रा निर्धारित कर रहे हैं और lexically scoped नहीं है, ताकि वहाँ है एक आंतरिक दायरे में दिए गए एक स्पष्ट हस्ताक्षर में एक बाहरी दायरे से एक कठोर प्रकार चर को संदर्भित करने का कोई तरीका नहीं है ... (ओह परेशान है, मुझे यकीन है कि कोई इसे इससे बेहतर वाक्यांश दे सकता है।) वैसे भी, प्रकार के चेकर के बिंदु से देखें, salpha के हस्ताक्षर में और wrapit के हस्ताक्षर में से एक पूरी तरह से असंबंधित है और इसे एकीकृत नहीं किया जा सकता है - इस प्रकार त्रुटि।

जीएचसी दस्तावेज़ों से और अधिक जानकारी के लिए हास्केल प्राइम विकी से this page देखें।

अद्यतन: मुझे अभी एहसास हुआ कि मैंने कभी समझाया नहीं कि पहला संस्करण क्यों काम करता है। पूर्णता के लिए: ध्यान दें कि पहले संस्करण के साथ, आप s के स्थान पर wrapit के हस्ताक्षर में t का उपयोग कर सकते हैं और कुछ भी नहीं बदलेगा। आप where ब्लॉक से wrapit भी ले सकते हैं और इसे एक अलग शीर्ष स्तर का फ़ंक्शन बना सकते हैं। मुख्य बिंदु यह है कि यह एक बहुलक कार्य है, ताकि wrapit x का प्रकार x के प्रकार से निर्धारित किया गया हो। alpha के हस्ताक्षर में उपयोग किए गए पहले संस्करण wrapit के हस्ताक्षर में उपयोग किए जाने वाले प्रकार परिवर्तक का कोई संबंध यहां किसी भी उपयोग का नहीं होगा। दूसरे संस्करण के साथ यह निश्चित रूप से अलग है और आपको wrapit के s को alpha के s जैसी ही चीज़ बनने के लिए उपरोक्त उल्लिखित चाल का सहारा लेना होगा।

+5

यह उत्तर बिल्कुल सही है, लेकिन मैं केवल जोर के लिए मुख्य बिंदु निकालना चाहता हूं: एक प्रकार के हस्ताक्षर में चर के पास उस हस्ताक्षर पर विस्तार होता है, न कि संबंधित परिभाषा के पूरे शरीर को। तो आपके उदाहरणों में से दो में से कोई भी असंबंधित नहीं है। 'ScopedTypeVariables' एक्सटेंशन 'नियम' के साथ स्पष्ट रूप से प्रमाणित चर के लिए इस नियम को संशोधित करता है। –

6

मीकल Marczyk का जवाब ऊपर सही है, लेकिन यह ध्यान देने योग्य बात है कि दूसरे संस्करण यदि आप wrapit समारोह के प्रकार के हस्ताक्षर को दूर काम करता है के लायक है:

data Wrapped a = Wrapped a 

alpha :: IO s -> IO() 
alpha x = do 
    rv <- wrapit 
    return() 
    where 
     -- No type signature here! 
     wrapit = do 
      a <- x 
      return (Wrapped a) 

है, समस्या के साथ नहीं है कोड स्वयं; यह है कि हास्केल 98 आपको wrapit फ़ंक्शन के लिए एक प्रकार का हस्ताक्षर लिखने नहीं देता है, क्योंकि इसमें इसके संदर्भ (बाहरी alpha फ़ंक्शन) द्वारा बाध्य एक प्रकार चर शामिल है, और H98 में इसे व्यक्त करने का कोई तरीका नहीं है।जैसा कि माइकल ने कहा, ScopedTypeVariables सक्षम करने से आप ऐसा करने की अनुमति देते हैं।

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