2016-08-27 9 views
20
Prelude> :i ($) 
($) :: 
    forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r). 
    (a -> b) -> a -> b 
     -- Defined in ‘GHC.Base’ 
infixr 0 $ 

(a -> b) -> a -> b से यह अलग कैसे है? क्या कोई b है जो नए प्रकार के हस्ताक्षर में फिट नहीं है?

+3

पुराना हस्ताक्षर वर्षों के लिए झूठ था। नया हस्ताक्षर वास्तव में अधिक सामान्य है, जिसमें उठाए गए प्रकार (प्रकार '*') और अनलिफ्ट किए गए दोनों शामिल हैं (पहले प्रकार '#'; अब और अधिक प्रकार में टूटा हुआ है)। – dfeuer

+8

एक सटीक डुप्लिकेट नहीं है (मुझे लगता है कि यह प्रश्न अधिक अद्यतित उत्तर से लाभान्वित हो सकता है), [यह उत्तर] (http://stackoverflow.com/a/35320729/465378) में कुछ जानकारी शामिल है जो चीजों को समझाने में मदद कर सकती है । –

+0

@sevo कौन सा भाषा एक्सटेंशन इसे चालू करता है? मैं इसके बारे में कुछ अन्य चर्चाओं से जानता था, लेकिन इसे ट्रिगर नहीं कर सकता। मुझे बस '($) :: (ए -> बी) -> ए -> बी' – Michael

उत्तर

4

8.0 से पहले, टाइपकेकर में $ से के प्रकार के काम करने के लिए आवेदन करने के लिए एक विशेष मामला था। इसका मतलब यह भी था कि आप अपने कार्यों को परिभाषित नहीं कर सके जो उठाए गए और बिना किसी प्रकार के दोनों के साथ काम कर सकते हैं। अब यह तथाकथित Levity Polymorphsim ('लेविटी' 'अनलिफ्ट' और 'उठाए गए' प्रकारों के कारण 'जिस डिग्री को उठाया गया है' - या 'उठाया गया' 'को संदर्भित करता है) टाइपशेकर में बनाया गया है, यह संभव है :

import GHC.Exts (TYPE, RuntimeRep(..)) 
import Data.Kind (type (*)) 

ap :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b) 
ap f x = f x 

ap_LP :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b) 
ap_LP f x = f x 

और वास्तव में $ समारोह अब हूबहू ap_LP को, typechecker में आवश्यक कोई विशेष मामले के साथ काम करता है unlifted प्रकार (लौटने typechecker में अभी भी एक विशेष मामला बनाने के लिए नहीं है के साथ $ काम करने के लिए परिभाषित किया गया है polymorphic आवेदन, यानी runST $ ... काम, लेकिन यह लेवी polymorphism से असंबंधित है)। यह अनिवार्य रूप से अतिरिक्त जटिलता का कारण है - अब सिस्टम सिस्टम में कम 'हैक्स' हैं, और जीएचसी के उपयोगकर्ता केवल उचित प्रकार के कार्य को देकर लेविटी पॉलिमॉर्फिज्म का लाभ उठा सकते हैं (ध्यान दें कि लेविटी-पॉलिमॉर्फिक प्रकार कभी अनुमानित नहीं होते हैं , जहाँ तक मैं बता सकता हूं)। लेविटी पॉलिमॉर्फिज्म से पहले, यदि आप एक पॉलिमॉर्फिक फ़ंक्शन लिखना चाहते थे जो कि उठाए गए और बिना किसी प्रकार के दोनों पर संभव काम कर सकता था, तो आप विभिन्न प्रकार के हस्ताक्षरों के साथ फ़ंक्शन की दो समान प्रतियां लिखने के लिए बाध्य थे।

नए प्रकार है कि में पुराने एक से अलग है नए प्रकार सख्ती से पुराने एक से अधिक सामान्य है:

-- ok 
ap' :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b) 
ap' = ap_LP 

-- type error: 
-- * Couldn't match a lifted type with an unlifted type 
ap_LP' :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b) 
ap_LP' = ap 

दूसरे शब्दों में, हर b जो 'फिट' पुराने हस्ताक्षर करना चाहिए (परिभाषा के द्वारा) नए प्रकार के हस्ताक्षर फिट (और इसलिए यह परिवर्तन पूरी तरह से पीछे की ओर संगत है!)।


भी ध्यान रखें कि निम्न नहीं संभव है:

ap'' :: forall (a :: TYPE r) (b :: *) . (a -> b) -> (a -> b) 
ap'' f x = f x 

उत्पादित त्रुटि

A representation-polymorphic type is not allowed here: 
    Type: a 
    Kind: TYPE r 
In the type of binder `x' 

है और SPJ प्रतिबंध here के लिए कारण बताते हैं:

यह बिल्कुल सही है कि दूसरे तर्क ($) में अनबॉक्सित प्रकार नहीं होना चाहिए। चूंकि ($) के लिए कोड (फ़ंक्शन पर पास) के आसपास उस तर्क को स्थानांतरित करना चाहिए, इसलिए इसे इसकी चौड़ाई, पॉइंटरहुड ect पता होना चाहिए।

लेकिन वास्तव में यह कॉल (एफ $ x) के परिणामस्वरूप अनबॉक्सित होने के लिए ठीक होगा, क्योंकि परिणाम ($) के लिए कोड परिणाम के साथ गड़बड़ नहीं करता है; यह सिर्फ पूंछ-कॉल एफ।

यह है कि नहीं हर छिछोरापन-बहुरूपी प्रकार एक वैध निवासी है कहने के लिए है - और इस अनबॉक्स्ड और बॉक्सिंग प्रकार के बीच परिचालन भेद है, जो कुछ मामलों में ही समान रूप से इलाज किया जा सकता से संबंधित है, और typechecker सुनिश्चित करती है इसका

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