2011-12-26 14 views
7

मैं LYAH के माध्यम से पढ़ रहा हूं, और अध्याय 9 में, मुझे एक जिज्ञासा समस्या मिली। लेखक "रैंडोम्स" फ़ंक्शन को लागू करने का एक उदाहरण प्रदान करता है:हास्केल: "रैंडम्स" लागू करें (ए.के.ए., अस्पष्ट प्रकार परिवर्तनीय)

randoms' :: (RandomGen g, Random a) => g -> [a] 
randoms' gen = let (value, newGen) = random gen in value:randoms' newGen 

अच्छा, यह ठीक है। लेकिन अगर मैं करने के लिए दूसरी पंक्ति बदलने के लिए: लोड हो रहा है पर

randoms' gen = (fst (random gen)) : (randoms' (snd (random gen))) 

इस फाइल को रिपोर्ट त्रुटि:

IOlesson.hs:4:52: 
    Ambiguous type variable `a' in the constraint: 
     `Random a' arising from a use of `random' at IOlesson.hs:4:52-61 
    Probable fix: add a type signature that fixes these type variable(s) 
Failed, modules loaded: none. 

अगर मैं इस लाइन को बदलने के लिए:

randoms' gen = (fst (random gen)) : (randoms' gen) 

तो यह सिर्फ क्या करेंगे ठीक है, और उम्मीद के अनुसार, यह सभी समान तत्वों की एक सूची वापस कर देगा।

मुझे परेशान है: मिरन के संस्करण और मेरे संस्करण में इतना अलग क्या है?

किसी भी विचार के लिए धन्यवाद!

उत्तर

7

समस्या यह है कि randomRandGen का कोई भी उदाहरण लेता है, और एक यादृच्छिक मान और उसी प्रकार का एक नया जनरेटर देता है। लेकिन यादृच्छिक मान Random के उदाहरण के साथ टाइप हो सकता है!

random :: (Random a, RandomGen g) => g -> (a, g) 

इसलिए, जब आप प्रत्यावर्तन में दूसरी बार random कहते हैं, यह क्या पहले तत्व के प्रकार होना चाहिए पता नहीं है! सच है, आप वास्तव में इसकी परवाह नहीं करते हैं (आप इसे snd के साथ फेंक देते हैं), लेकिन की पसंद व्यवहारrandom को प्रभावित कर सकती है। तो असंबद्ध करने के लिए, आपको जीएचसी को बताना होगा कि आप होना चाहते हैं। - के तत्व प्रकार

randoms' gen = let (value, gen') = random gen in value : randoms' gen' 

क्योंकि आप जिसके परिणामस्वरूप सूची के भाग के रूप value उपयोग करें, यह एक अपने प्रकार हस्ताक्षर में के रूप में एक ही प्रकार है करने के लिए मजबूर कर रहा है: सबसे आसान तरीका है इस प्रकार अपनी परिभाषा को फिर से लिखने के लिए है परिणामस्वरूप सूची। अस्पष्टता हल हो जाती है, और बूट करने के लिए, अगले यादृच्छिक संख्या की डुप्लिकेट गणना से बचा जाता है। इसे और अधिक सीधे (डुप्लिकेट गणना को ध्यान में रखते हुए) को अलग करने के तरीके हैं, लेकिन वे या तो बदसूरत और उलझन में हैं या भाषा एक्सटेंशन शामिल हैं। शुक्र है, आपको अक्सर इसमें भाग नहीं लेना चाहिए, और जब आप ऐसा करते हैं, तो इस तरह की एक विधि अस्पष्टता को हल करने के लिए काम करनी चाहिए।

इसके तुल्य और शायद अधिक बड़े करीने से, आप लिख सकते हैं:

randoms' gen = value : randoms' gen' 
    where (value, gen') = random gen 
+0

धन्यवाद! यह इतना काउंटर अंतर्ज्ञानी है, फिर भी पूरी तरह समझ में आता है। –

+0

आपका स्वागत है; टाइपक्लास अस्पष्टता त्रुटियां पहली बार मुश्किल हो सकती हैं, लेकिन आपको जल्द ही उन्हें लटका देना चाहिए :) – ehird

4

random के प्रकार पर विचार करें:

random :: (RandomGen g, Random a) => g -> (a, g) 

परिणाम टपल Random का एक उदाहरण है कि किसी भी प्रकार की एक मूल्य के होते हैं, और अद्यतन आरएनजी मूल्य। महत्वपूर्ण हिस्सा "कोई भी उदाहरण" है: किसी भी प्रकार के मान का उत्पादन करने के लिए random दोनों के उपयोग के लिए कुछ भी आवश्यक नहीं है।

fst (random gen) में कोई समस्या नहीं है, क्योंकि उत्पन्न मूल्य जो भी पूरे कार्य की आवश्यकता है; snd (random gen) में, हालांकि, यादृच्छिक मूल्य फेंक दिया गया है, इसलिए यह पूरी तरह से अज्ञात है कि यह किस प्रकार होना चाहिए। इस प्रकार को जानने के बिना, हास्केल उपयोग करने के लिए उचित Random उदाहरण का चयन नहीं कर सकता है, इसलिए आप देखे गए अस्पष्ट प्रकार की त्रुटि।

1

random प्रकार का है: RandomGen g => g -> (a, g)

और इसलिए snd (random gen) ही प्रकार g -> g की है। और फिर यह नहीं पता कि a क्या है। प्रत्येक डेटाटाइप के लिए एक अलग random है जो आप उत्पन्न करना चाहते हैं, लेकिन इस मामले में संकलक यह नहीं जानता कि आप random :: g -> (Int,g) या random :: g->(Char,g) या कुछ और चाहते हैं।

यह मट्ठा (value, newGen) = random gen काम करता है। यह संकलक को a के बारे में जानकारी के साथ जुड़ने में मदद करता है। valuea टाइप होना चाहिए और इसलिए यह random gen के प्रकार को घटा सकता है।

(संपादित:। मुझे लगता है मैं यह तय करने में किए गए एक गलत प्रयास नष्ट कर दिया बस प्रश्न में मूल कोड के साथ चिपके रहते हैं!)

+1

उस फिक्स को टाइप हस्ताक्षर में '{- # LANGUAGE स्कॉप्ड टाइप टाइपरी # -}' और एक स्पष्ट 'forall' की आवश्यकता है। – ehird

+0

(मैं विस्तार से क्या हूं और क्या नहीं है इसके विवरण में विशेषज्ञ से बहुत दूर हूं) मैं उस @ehird पर हैरान हूं, टाइप वैरिएबल 'ए' पहले से ही हस्ताक्षर प्रकार में है। मैं बस 'यादृच्छिक जीन' अभिव्यक्ति के प्रकार को स्पष्ट रूप से निर्दिष्ट करने के लिए इसका उपयोग कर रहा हूं। मैंने सोचा होगा कि यह बहुत मानक हास्केल था। –

+0

मानक हास्केल में, जब भी आप किसी नए क्षेत्र में '::' के बाद एक प्रकार चर का उपयोग करते हैं। यह बहुत मूर्ख है। – ehird

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