2011-08-16 17 views
12

मैं हैकेल टाइपसिस्टम की नीची किरदार में जा रहा हूं और प्रकार के वर्गों के ठीक बिंदुओं पर पहुंचने की कोशिश कर रहा हूं। मैंने एक ढेर सीखा है, लेकिन मैं कोड के निम्नलिखित टुकड़ों पर एक दीवार मार रहा हूँ।हास्केल प्रकार प्रणाली nuances

इन क्लास और उदाहरण परिभाषाओं का उपयोग करना:

लेकिन यह नहीं करता है:

class Show a => C a where 
    f :: Int -> a 

instance C Integer where 
    f x = 1 

instance C Char where 
    f x = if x < 10 then 'c' else 'd' 

ऐसा क्यों है कि इस प्रकार के चेकर गुजरता है?

g :: C a => a -> Int -> String 
g x y = show(f y) 

मुझे दूसरा विकल्प अधिक पढ़ने योग्य लगता है, और ऐसा लगता है कि यह केवल मामूली अंतर है (प्रकार हस्ताक्षर नोट करें)। हालांकि, टाइपशेकर के पिछले अतीत को प्राप्त करने का प्रयास करने में परिणाम:

*Main> :l typetests.hs 
[1 of 1] Compiling Main    (typetests.hs, interpreted) 

typetests.hs:11:14: 
    Ambiguous type variable `a0' in the constraints: 
     (C a0) arising from a use of `f' at typetests.hs:11:14 
     (Show a0) arising from a use of `show' at typetests.hs:11:9-12 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the first argument of `show', namely `(f y)' 
    In the expression: show (f y) 
    In an equation for `g': g x y = show (f y) 
Failed, modules loaded: none. 

और मुझे समझ में नहीं आता क्यों।

नोट: कृपया पूछें कि "आप क्या करने की कोशिश कर रहे हैं?" मुझे उम्मीद है कि यह स्पष्ट है कि मैं इस भाषा के काम के तरीके की जांच करने के लिए एक अमूर्त संदर्भ में बस गड़बड़ कर रहा हूं। मेरे पास कुछ नया सीखने के अलावा दिमाग में कोई लक्ष्य नहीं है।

धन्यवाद

+3

खूनी नरक! एसओ पर पहली पोस्ट और मुझे 24 घंटों से कम समय में तीन महान और अंतर्दृष्टिपूर्ण उत्तर मिलते हैं। यह जगह अद्भुत है। धन्यवाद दोस्तों – TheIronKnuckle

उत्तर

21

यह वह जगह है जहां एक मजेदार खिलौना खेलता है। मानक प्रीलूड फ़ंक्शन asTypeOf पर विचार करें।

asTypeOf :: a -> a -> a 
asTypeOf = const 

यह सिर्फ अपनी पहली तर्क, कोई बात नहीं क्या दूसरा तर्क है देता है। लेकिन उस पर प्रकार हस्ताक्षर अतिरिक्त बाधा डालता है कि इसके दोनों तर्क एक ही प्रकार के होना चाहिए।

g :: C a => a -> Int -> String 
g x y = show (f y `asTypeOf` x) 

अब, GHC जानता है क्या f y का प्रकार है। यह g पर पहले तर्क के प्रकार जैसा ही है। उस जानकारी के बिना, आपको, आपके द्वारा देखा गया त्रुटि संदेश मिलता है। f y के प्रकार को निर्धारित करने के लिए पर्याप्त जानकारी नहीं थी। और क्योंकि यह प्रकार महत्वपूर्ण है (यह निर्धारित करने के लिए प्रयोग किया जाता है कि show के लिए किस उदाहरण का उपयोग करना है), जीएचसी को यह जानने की जरूरत है कि कोड उत्पन्न करने के लिए आपका क्या मतलब है।

16

g :: C a => a -> Int -> a 
g x y = f y 

में f y की वापसी प्रकार प्रकार हस्ताक्षर द्वारा तय हो गई है, इसलिए है कि अगर आप कहते हैं, जैसे g 'a' 3, instance C Char का उपयोग किया जाएगा। लेकिन

g :: C a => a -> Int -> String 
g x y = show(f y) 

में वहाँ f की वापसी प्रकार पर दो की कमी कर रहे हैं: यह C (ताकि f इस्तेमाल किया जा सकता) एक उदाहरण होना चाहिए और Show की (कि show इसलिए इस्तेमाल किया जा सकता है)। और बस यही! f और g की परिभाषाओं में प्रकार परिवर्तनीय नाम a का संयोग कोई मतलब नहीं है। तो कंपाइलर के पास instance C Char और instance C Integer (या अन्य मॉड्यूल में परिभाषित किसी भी उदाहरण के बीच चयन करने का कोई तरीका नहीं है, इसलिए इन उदाहरणों को हटाने से कार्यक्रम संकलित नहीं होगा)।

21

यह कुख्यात show . read समस्या का एक रूप है। क्लासिक संस्करण

read :: Read a => String -> a 
show :: Show a => a -> String 

उपयोग करता है ताकि रचना एक सादे पुराने स्ट्रिंग ट्रांसड्यूसर जैसा लग सकता है

moo :: String -> String 
moo = show . read 

कार्यक्रम में कोई जानकारी नहीं बीच में प्रकार, इसलिए क्या करने के लिए निर्धारित करने के लिए है, सिवाय इसके कि वहाँ read और फिर show

Ambiguous type variable `b' in the constraints: 
    `Read b' arising from a use of `read' at ... 
    `Show b' arising from a use of `show' at ... 
Probable fix: add a type signature that fixes these type variable(s) 

कृपया यह नहीं कि ghci पागल अतिरिक्त डिफॉल्टिंग का एक गुच्छा करता है, मनमाने ढंग से अस्पष्टता को हल करता है। सिवाय इसके कि यह एक Int डीकोड बजाय एक String पढ़ने की, लेकिन समस्या यह मूलतः एक ही है

> (show . read) "()" 
"()" 

आपका C वर्ग, Read का एक संस्करण है।

टाइप सिस्टम उत्साही नोट करेंगे कि अंडरग्रेन किए गए प्रकार चर प्रति से एक बड़ा सौदा नहीं है। यह अस्पष्ट उदाहरण अनुमान है जो यहां समस्या है। पर विचार करें

poo :: String -> a -> a 
poo _ = id 

qoo :: (a -> a) -> String 
qoo _ = "" 

roo :: String -> String 
roo = qoo . poo 

roo के निर्माण में, यह निर्धारित किया जाता है कभी नहीं क्या बीच में प्रकार होना चाहिए, और न ही roo है कि प्रकार में बहुरूपी है। अनुमान टाइप करें न तो हल करता है और न ही चर को सामान्य करता है! फिर भी,

> roo "magoo" 
"" 

यह नहीं एक समस्या है, क्योंकि निर्माण अज्ञात प्रकार में पैरामीट्रिक है। तथ्य यह है कि इस प्रकार का निर्धारण नहीं किया जा सकता है जिसके परिणामस्वरूप का प्रकार नहीं हो सकता है।

लेकिन अज्ञात उदाहरण स्पष्ट रूप से कोई फर्क नहीं पड़ता। हिंडली-मिलनर प्रकार के अनुमान के लिए पूर्णता परिणाम पैरामीट्रिकिटी पर निर्भर करता है और जब हम ओवरलोडिंग जोड़ते हैं तो इस प्रकार खो जाता है। चलो इसके लिए रोना नहीं है।

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