2012-04-27 10 views
17

को देखते हुए निम्नलिखित परिभाषा:हास्केल रैंक दो बहुरूपता संकलन त्रुटि

import Control.Monad.ST 
import Data.STRef 

fourty_two = do 
    x <- newSTRef (42::Int) 
    readSTRef x 

GHC के अंतर्गत निम्नलिखित compiles:

main = (print . runST) fourty_two -- (1) 

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

main = (print . runST) $ fourty_two -- (2) 

लेकिन तब के रूप में bdonlan एक टिप्पणी में बताते हैं, यह संकलित करता है:

main = ((print . runST) $) fourty_two -- (3) 

लेकिन, इस

main = (($) (print . runST)) fourty_two -- (4) 

कौन सा संकेत मिलता है कि (3) केवल इन्फ़िक्स $ की विशेष उपचार की वजह से संकलित लगता है संकलन नहीं करता है, लेकिन यह अभी भी स्पष्ट नहीं होता क्यों (1) संकलन करता है

सवाल:

1) मैं निम्नलिखित दो सवाल (first, second) पढ़ा है, और मुझे विश्वास है $ केवल monomorphic प्रकार के साथ instantiated किया जा सकता है का नेतृत्व कर रहे थे। लेकिन मैं इसी तरह मानता हूं कि . केवल मोनोमोर्फिक प्रकारों के साथ तत्काल हो सकता है, और परिणामस्वरूप भी असफल हो जाएगा। पहला कोड सफल क्यों होता है लेकिन दूसरा कोड नहीं होता है? (उदाहरण के लिए क्या एक विशेष नियम जीएचसी के पहले मामले में है कि यह दूसरे में लागू नहीं हो सकता है?)

2) क्या कोई मौजूदा जीएचसी एक्सटेंशन है जो दूसरे कोड को संकलित करता है? (शायद ImpredicativePolymorphism कुछ बिंदु पर यह काम किया है, लेकिन यह पदावनत लगता है, कुछ भी बदल दिया गया है?)

3) वहाँ क्या $ करता है वह करने GHC एक्सटेंशन का उपयोग `my_dollar` कहना निर्धारित करने का कोई रास्ता नहीं है, लेकिन यह भी बहुरूपी संभाल करने में सक्षम है प्रकार, तो (print . runST) `my_dollar` fourty_two संकलन?

संपादित करें: प्रस्तावित उत्तर:

main = ((.) print runST) fourty_two -- (5) 

इस रूप में (1), . की इन्फ़िक्स संस्करण का उपयोग नहीं सिवाय एक ही है:

इसके अलावा, निम्नलिखित संकलित करने के लिए विफल रहता है।

परिणामस्वरूप, ऐसा लगता है कि जीएचसी के पास $ और . दोनों के लिए विशेष नियम हैं, लेकिन केवल उनके इन्फिक्स संस्करण हैं।

+2

यह और भी दिलचस्प, '((प्रिंट runST) $।) बनाने के fourty_two' _does_ काम – bdonlan

+0

यह दिलचस्प है और आगे चीजें confuses! – Clinton

+0

मैं काफी हद तक निश्चित हूं कि जीएचसी में 'रनस्ट $ डू' मामले का समर्थन करने के लिए एक विशेष नियम है, लेकिन अब मुझे कोई उद्धरण नहीं मिला है। –

उत्तर

6
  1. मुझे यकीन नहीं है कि मैं समझता हूं कि दूसरा क्यों काम नहीं करता है। हम print . runST के प्रकार को देख सकते हैं और देख सकते हैं कि यह पर्याप्त रूप से बहुलक है, इसलिए दोष (.) के साथ नहीं है। मुझे संदेह है कि जीएचसी का विशेष नियम इंफिक्स ($) के लिए है, बस इतना पर्याप्त नहीं है। एसपीजे और दोस्त इसे फिर से जांचने के लिए खुले हो सकते हैं यदि आप अपने ट्रैकर पर एक बग के रूप में इस खंड को प्रस्तावित करते हैं।

    क्यों तीसरा उदाहरण काम करता है, ठीक है, कि सिर्फ इसलिए कि फिर से ((print . runST) $) के प्रकार के लिए पर्याप्त रूप से बहुरूपी है के लिए के रूप में, वास्तव में, यह print . runST के प्रकार के बराबर है।

  2. कुछ भी ImpredicativePolymorphism को प्रतिस्थापित नहीं किया गया है, क्योंकि जीएचसी लोगों ने किसी भी उपयोग के मामलों को नहीं देखा है जहां अतिरिक्त प्रोग्रामर सुविधा ने कंपाइलर कीड़े के लिए अतिरिक्त क्षमता को अधिक कर दिया है। (मुझे नहीं लगता कि वे इस रूप में सम्मोहक देखना चाहते हैं, या तो, हालांकि निश्चित रूप से मैं अधिकार नहीं हूँ।)
  3. हम एक थोड़ा कम बहुरूपी ($$) परिभाषित कर सकते हैं:

    {-# LANGUAGE RankNTypes #-} 
    infixl 0 $$ 
    ($$) :: ((forall s. f s a) -> b) -> ((forall s. f s a) -> b) 
    f $$ x = f x 
    

    फिर अपने उदाहरण इस नए ऑपरेटर के साथ ठीक typechecks:

    *Main> (print . runST) $$ fourty_two 
    42 
    
0

मैं इस विषय पर बहुत अधिक अधिकार के साथ यहाँ नहीं कह सकता, लेकिन क्या मुझे लगता है कि ऐसा हो सकता है:

पर विचार करें typechecker इन मामलों में से प्रत्येक में क्या करना है क्या। (print . runST) में Show b => (forall s. ST s t) -> IO() है। fourty_two में ST x Int है।

forall यहाँ एक अस्तित्व प्रकार क्वालीफायर है - यहां इसका मतलब यह है कि दिया गया तर्क सार्वभौमिकs पर हो गया है।यही है, आपको एक पॉलिमॉर्फिक प्रकार में गुजरना होगा जो s के लिए किसी भी मूल्य का समर्थन करता है। यदि आप स्पष्ट रूप से forall नहीं बताते हैं, तो हास्केल इसे टाइप परिभाषा के बाहरीतम स्तर पर रखता है। इसका मतलब है कि fourty_two :: forall x. ST x Int और (print . runST) :: forall t. Show t => (forall s. ST s t) -> IO()

अब, हम दे t = Int, x = s द्वारा forall s. ST s t साथ forall x. ST x Int मिलान कर सकते हैं। तो प्रत्यक्ष कॉल केस काम करता है। यदि हम $ का उपयोग करते हैं, तो क्या होगा?

$ टाइप ($) :: forall a b. (a -> b) -> a -> b है। इसलिए ($) :: forall x t. (a = forall s. ST s t -> b = IO()) -> (a = ST x t) -> IO() - जब हम हल a और b, के बाद से $ के लिए प्रकार इस तरह किसी भी स्पष्ट प्रकार scoping नहीं है, fourty_two की x तर्क ($) के लिए प्रकार में सबसे बाहरी गुंजाइश के लिए बाहर उठा लिया जाता है। इस बिंदु पर, यह a और b से मेल खाता है, और विफल रहता है।

आप के बजाय ((print . runST) $) fourty_two लिखते हैं, तो संकलक पहले ((print . runST $) के प्रकार के हल करता है। यह forall t. (a = forall s. ST s t -> b = IO()) -> a -> b होने के लिए ($) के प्रकार को हल करता है; ध्यान दें कि a के दूसरे मौके के बाद से अनजान है, हमारे पास उस बड़े पैमाने पर टाइप वैरिएबल को बाहरीतम दायरे में नहीं ले जाया गया है! और इसलिए मैच सफल होता है, फ़ंक्शन आंशिक रूप से लागू होता है, और अभिव्यक्ति का समग्र प्रकार forall t. (forall s. ST s t) -> IO() है, जो ठीक है, जहां हमने शुरू किया था, और इसलिए यह सफल हुआ।

+0

दूसरे अंतिम पैराग्राफ में, मुझे समझ में नहीं आता कि क्यों 'x' "उठाया जाता है"। कंपाइलर द्वारा निर्मित वास्तविक प्रकार 'x' नहीं है? जो मैं समझता हूं, उससे एक छिपी हुई प्रकार है जिसे हम कभी भी एक्सेस नहीं कर सकते हैं, लेकिन यह 'Int' जैसा है। हम 'Int' नहीं उठाते हैं, क्यों 'x' उठाते हैं? – Clinton

+0

यानी 'x' वास्तव में' X12345' नहीं है, संकलक द्वारा उत्पन्न वास्तविक प्रकार (हालांकि हमें इसकी पहुंच कभी नहीं होगी)? – Clinton

+0

@ क्लिंटन, 'x' एक प्रकार नहीं है, यह एक प्रकार चर है। और मुझे यकीन नहीं है कि यह 'चौथाई_टीवो' पर' ... $ ... 'अभिव्यक्ति प्रकार के बाहरी स्तर पर अंतर्निहित मात्रा को उठाने का विकल्प क्यों चुनता है। आप 'Int' की मात्रा को उठा नहीं सकते हैं, हालांकि, क्योंकि यह एक प्रकार परिवर्तनीय नहीं है, यह एक प्रकार है। – bdonlan