2015-10-31 2 views
5

जबकि GHC एक्सटेंशन के माध्यम से अपने रास्ते से काम कर रहा है, मैं RankNTypes at the School of Haskell, जो था निम्न उदाहरण में आए अंतर यह है कि "उत्तरार्द्ध हस्ताक्षर के लिए कुछ Num n के लिए एन से एन के लिए एक फ़ंक्शन की आवश्यकता होती है; पूर्व हस्ताक्षर को प्रत्येक Num n के लिए n से n के लिए एक फ़ंक्शन की आवश्यकता होती है।"समझौता हास्केल के RankNTypes

मैं समझ सकता हूं कि पूर्व प्रकार को कोष्ठक या अधिक सामान्य में होने के लिए हस्ताक्षर की आवश्यकता होती है। मैं स्पष्टीकरण को समझ नहीं पा रहा हूं कि बाद वाले हस्ताक्षर को केवल कुछ Num n "के लिए n -> n फ़ंक्शन की आवश्यकता होती है। क्या कोई विस्तार और स्पष्टीकरण दे सकता है? आप इस पूर्व हस्ताक्षर को "कैसे पढ़ते हैं" ताकि ऐसा लगता है कि इसका क्या अर्थ है? क्या बाद वाला हस्ताक्षर के समान forall की आवश्यकता के बिना है?

+0

फ़ंक्शन के शरीर के बारे में सोचें: '(एफ (1 :: इंट), एफ (1.0 :: डबल))'। आप इसके लिए बाद के प्रकार हस्ताक्षर का उपयोग नहीं कर सकते हैं। 'Num n => n -> n -> (Int, Double) 'में आपके पास' n' एक ही समय में 'Int' और' Double' * होना चाहिए *। '(Forall n। Num n => n -> n) -> (Int, Double) 'का उपयोग करना आपके पास है कि फ़ंक्शन' f' को विभिन्न प्रकारों पर लागू किया जा सकता है और इस प्रकार यह अच्छी तरह टाइप किया गया है। – Bakuriu

उत्तर

6

सामान्य मामले (forall n. Num n => (n -> n) -> (Int, Double)), हम एक nपहले चयन में और फिर एक समारोह प्रदान करते हैं। तो हम Int -> Int, Double -> Double, Rational -> Rational और इसी प्रकार के फ़ंक्शन में पास हो सकते हैं।

रैंक 2 मामले ((forall n. Num n => n -> n) -> (Int, Double)) हम इससे पहले कि हम जानते हैं कि n समारोह प्रदान करने के लिए है। इसका मतलब है कि फ़ंक्शन को किसी भीn के लिए काम करना है; पिछले उदाहरण के लिए सूचीबद्ध उदाहरणों में से कोई भी काम नहीं करेगा।

हमें इसे उदाहरण कोड के लिए चाहिए क्योंकि फ़ंक्शन f जो पारित किया गया है, दो अलग-अलग प्रकारों पर लागू होता है: Int और Double। तो इसे दोनों के लिए काम करना है।

पहला मामला सामान्य है क्योंकि इस तरह प्रकार प्रकार चर डिफ़ॉल्ट रूप से काम करते हैं। यदि आपके पास forall बिल्कुल नहीं है, तो आपका प्रकार हस्ताक्षर बहुत शुरुआत में बराबर है। (इसे पेंडेक्स रूप कहा जाता है।) तो Num n => (n -> n) -> (Int, Double) स्पष्ट रूप से forall n. Num n => (n -> n) -> (Int, Double) जैसा ही है।

n के लिए काम करने वाले फ़ंक्शन का प्रकार क्या है? यह बिल्कुल forall n. Num n => n -> n है।

+0

अपडेट किया गया धन्यवाद। "रैंक एन" में, रैंक का क्या मतलब है और एन क्या संदर्भित करता है? – Ana

+1

'एन' संदर्भित करता है कि आप कार्यों के अंदर 'फॉरल' घोंसला कैसे कर सकते हैं (' -> ')। इस मामले में, यह एक ही समारोह के अंदर घोंसला है, इसलिए यह रैंक 2 होगा। हास्केल * केवल * समर्थन रैंक 2 बहुरूपता का समर्थन करता है लेकिन चूंकि यह अब मनमाने ढंग से रैंकों का समर्थन करता है, यह एक ऐतिहासिक नोट है। –

2

आप इस पूर्व हस्ताक्षर को "कैसे पढ़ते हैं" ताकि यह कैसा लगता है?

आप

rankN :: (forall n. Num n => n -> n) -> (Int, Double) 

पढ़ सकते हैं के रूप में "rankN एक पैरामीटर f :: Num n => n -> n लेता है" और (Int, Double), जहां f :: Num n => n -> n किसी भी सांख्यिक प्रकार n के लिए "के रूप में पढ़ा जा सकता है देता है, f एक n लेने के लिए और एक n लौट सकते हैं "।

रैंक एक परिभाषा

rank1 :: forall n. Num n => (n -> n) -> (Int, Double) 

तो के रूप में पढ़ा की जाएगी "किसी भी सांख्यिक प्रकार n के लिए, rank1 एक तर्क f :: n -> n लेता है और एक (Int, Double) रिटर्न"।

क्या बाद में हस्ताक्षर Num n => (n -> n) -> (Int, Double) के समान forall की आवश्यकता के बिना है?

हां, डिफ़ॉल्ट रूप से सभी forall एस बाहरी रूप से बाहरी स्थिति (जिसके परिणामस्वरूप रैंक -1 प्रकार) में निहित हैं।

2

rankN मामले f में एक पॉलीमोर्फिक फ़ंक्शन होना चाहिए जो सभी संख्यात्मक प्रकारों n के लिए मान्य है।

rank1 मामले f में केवल एक संख्यात्मक प्रकार के लिए परिभाषित किया जाना है।

यहाँ कुछ कोड है जो इस को दिखाता है:

{-# LANGUAGE RankNTypes #-} 

rankN :: (forall n. Num n => n -> n) -> (Int, Double) 
rankN = undefined 

rank1 :: forall n. Num n => (n -> n) -> (Int, Double) 
rank1 = undefined 

foo :: Int -> Int -- monomorphic 
foo n = n + 1 

test1 = rank1 foo -- OK 

test2 = rankN foo -- does not type check 

test3 = rankN (+1) -- OK since (+1) is polymorphic 

अद्यतन

जवाब में टिप्पणी में @ helpwithhaskell के सवाल का ...

bar :: (forall n. Num n => n -> n) -> (Int, Double) -> (Int, Double) 
bar f (i,d) = (f i, f d) 

है, हम दोनों एक इंट और एक डबल करने के लिए f लागू होते हैं:

इस समारोह पर विचार करें। RankNTypes का उपयोग कर के बिना यह जांच टाइप नहीं होगा:

??? निम्नलिखित हस्ताक्षर काम के
-- doesn't work 
bar' :: ??? -> (Int, Double) -> (Int, Double) 
bar' f (i,d) = (f i, f d) 

कोई नहीं:

Num n => (n -> n) 
Int -> Int 
Double -> Double 
+0

कोई रैंक एन केस क्यों चाहेंगे? पॉलिमॉर्फिक पैरामीटर की आवश्यकता के लिए क्या लाभ होता है? – helpwithhaskell

+0

@helpwithhaskell - उत्तर – ErikR

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