2013-11-26 5 views
6

मैं हाल ही में vinyl पर पढ़ रहा हूं, जो कि अजीब "प्रकारों की सूची" प्रकारों का उपयोग करता है। प्रकार और विनाइल पर थोड़ा पढ़ने के बाद, मैं उनमें से एक सहज ज्ञान युक्त समझ के कुछ मिल गया है, और मैं इस एक साथदयालु सूचियां कैसे काम करती हैं?

{-# LANGUAGE DataKinds, 
      TypeOperators, 
      FlexibleInstances, 
      FlexibleContexts, 
      KindSignatures, 
      GADTs #-} 
module Main where 

-- from the data kinds page, with HCons replaced with :+: 
data HList :: [*] -> * where 
    HNil :: HList '[] 
    (:+:) :: a -> HList t -> HList (a ': t) 

infixr 8 :+: 


instance Show (HList '[]) where 
    show _ = "[]" 
instance (Show a, Show (HList t)) => Show (HList (a ': t)) where 
    show (x :+: xs) = show x ++ " : " ++ show xs 

class ISum a where 
    isum :: Integral t => a -> t 

instance ISum (HList '[]) where 
    isum _ = 0 


instance (Integral a, ISum (HList t)) => ISum (HList (a ': t)) where 
    isum (x :+: xs) = fromIntegral x + isum xs 

-- explicit type signatures just to check if I got them right 
alist :: HList '[Integer] 
alist = (3::Integer) :+: HNil 

blist :: HList '[Integer,Int] 
blist = (3::Integer) :+: (3::Int) :+: HNil 

main :: IO() 
main = do 
    print alist 
    print (isum alist :: Int) 
    print blist 
    print (isum blist :: Integer) 

:i HList हैक कर लिया है पैदावार

data HList $a where 
    HNil :: HList ('[] *) 
    (:+:) :: a -> (HList t) -> HList ((':) * a t) 
    -- Defined at /tmp/test.hs:10:6 
instance Show (HList ('[] *)) -- Defined at /tmp/test.hs:17:10 
instance (Show a, Show (HList t)) => Show (HList ((':) * a t)) 
    -- Defined at /tmp/test.hs:19:10 
instance ISum (HList ('[] *)) -- Defined at /tmp/test.hs:25:10 
instance (Integral a, ISum (HList t)) => ISum (HList ((':) * a t)) 
    -- Defined at /tmp/test.hs:29:10 
*Main> :i HList 
data HList $a where 
    HNil :: HList ('[] *) 
    (:+:) :: a -> (HList t) -> HList ((':) * a t) 
    -- Defined at /tmp/test.hs:10:6 
instance Show (HList ('[] *)) -- Defined at /tmp/test.hs:17:10 
instance (Show a, Show (HList t)) => Show (HList ((':) * a t)) 
    -- Defined at /tmp/test.hs:19:10 
instance ISum (HList ('[] *)) -- Defined at /tmp/test.hs:25:10 
instance (Integral a, ISum (HList t)) => ISum (HList ((':) * a t)) 
    -- Defined at /tmp/test.hs:29:10 

जहां से मैं '[]'[] * और x ': y के लिए (':) * x y के लिए चीनी है। वह क्या है * वहां कर रहा है? क्या यह सूची तत्वों की तरह है? इसके अलावा, वैसे भी ऐसी सूची क्या है? क्या यह भाषा में कुछ बनाया गया है?

उत्तर

7

* है ... दुर्भाग्यपूर्ण। यह पॉलीकिज्ड डेटा प्रकारों के लिए जीएचसी के सुंदर प्रिंटर का नतीजा है। यह उन चीज़ों में परिणाम देता है जो वाक्य के रूप में सिंटेक्टिक रूप से अमान्य हैं, लेकिन यह कुछ उपयोगी जानकारी व्यक्त करता है।

जब जीएचसी पॉलीमोर्फिक प्रकारों के साथ एक प्रकार को प्रिंट करता है, तो यह टाइप कन्स्ट्रक्टर के बाद प्रत्येक पॉलीमोर्फिक प्रकार चर के प्रकार को प्रिंट करता है। क्रम में। तो अगर आप की तरह एक घोषणा थी:

data Foo (x :: k) y (z :: k2) = Foo y 

GHC y -> Foo k k1 x y z रूप Foo के प्रकार (डेटा निर्माता) बहुत-प्रिंट होगा। आप कुछ का उपयोग .. कि नीचे कुछ हद तक उन प्रकार चर, जैसे में से एक की तरह पिन किया गया था, तो

foo :: a -> Int -> Foo a Int 5 -- Data Kind promoted Nat 

foo "hello" 0 के प्रकार Foo * Nat String Int 5 के रूप में मुद्रित किया जाएगा। हाँ, यह भयानक है। लेकिन अगर आप जानते हैं कि क्या हो रहा है, कम से कम आप इसे पढ़ सकते हैं।

'[] सामान DataKinds एक्सटेंशन का हिस्सा है। यह प्रकारों को प्रकारों को बढ़ावा देने की अनुमति देता है, और उस प्रकार के निर्माता टाइपर कन्स्ट्रक्टर बन जाते हैं। उन प्रचारित प्रकारों के पास कोई वैध मान नहीं है, न कि undefined, क्योंकि उनकी तरह * के साथ संगत नहीं है, जो कि उन सभी प्रकारों के प्रकार हैं जिनके साथ मूल्य हो सकते हैं। इसलिए वे केवल उन स्थानों पर दिखाई दे सकते हैं जहां उस मूल्य का कोई प्रकार नहीं है।

आपकी टिप्पणी रास्ता GHCi कार्यों के बारे में कुछ बातों को लाता है: अधिक जानकारी के लिए, http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/kind-polymorphism-and-promotion.html

संपादित करें।

-- foo.hs 
{-# LANGUAGE DataKinds, PolyKinds #-} 

data Foo (x :: k) y (z :: k1) = Foo y 

जब आप GHCi में एक फ़ाइल को लोड, यह एक्सटेंशन सहभागी है कि फाइल में इस्तेमाल किया गया सक्रिय नहीं है।

GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Prelude> :l foo 
[1 of 1] Compiling Main    (foo.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> :t Foo 
Foo :: y -> Foo * * x y z 
*Main> :set -XPolyKinds 
*Main> :t Foo 
Foo :: y -> Foo k k1 x y z 

तो, हाँ। PolyKinds विस्तार ghci में इसके लिए पॉलिमॉर्फिक प्रकारों के लिए डिफ़ॉल्ट रूप से सक्षम होना चाहिए। और मैंने फ़ाइल में अपने foo फ़ंक्शन को परिभाषित करने का प्रयास किया, लेकिन यह वास्तव में ghc के इस संस्करण को क्रैश कर दिया। ओह। मुझे लगता है कि अब तय है, लेकिन मुझे लगता है कि ghc trac की जांच करना अच्छा होगा। किसी भी मामले में, मैं इसे अंतःक्रियात्मक रूप से परिभाषित कर सकता हूं और यह ठीक काम करता है।

*Main> :set -XDataKinds 
*Main> let foo :: a -> Int -> Foo a Int 5 ; foo = undefined 
*Main> :t foo "hello" 0 
foo "hello" 0 :: Foo * GHC.TypeLits.Nat [Char] Int 5 
*Main> :m + GHC.TypeLits 
*Main GHC.TypeLits> :t foo "hello" 0 
foo "hello" 0 :: Foo * Nat [Char] Int 5 

ठीक है, ठीक है, मैं भूल गया यह Nat अयोग्य प्रदर्शित करने के लिए आयात की जरूरत थी।और चूंकि मैं केवल प्रिंटिंग का प्रदर्शन कर रहा था, इसलिए मुझे एक कार्यान्वयन की परवाह नहीं थी, इसलिए undefined पर्याप्त है।

लेकिन सब कुछ काम करता है मैंने कैसे कहा, मैं वादा करता हूं। मैंने अभी कुछ विवरण छोड़े हैं कि किस एक्सटेंशन की आवश्यकता थी, विशेष रूप से PolyKinds और DataKinds दोनों में। मैंने माना कि चूंकि आप अपने कोड में उन लोगों का उपयोग कर रहे थे, इसलिए आप उन्हें समझ गए। PolyKinds एक्सटेंशन पर प्रलेखन यहां दिया गया है: http://www.haskell.org/ghc/docs/7.6.3/html/users_guide/kind-polymorphism.html

+0

बहुत स्पष्ट! मैं अब कुछ समय के लिए इस वाक्यविन्यास को पूरी तरह से प्राप्त करने के साथ संघर्ष कर रहा हूं। –

+1

मैं वास्तव में इस उत्तर के अधिकांश को समझ नहीं पा रहा हूं।आपका उदाहरण केवल मेरे लिए -XPolyKinds के साथ काम करता है - एक और एक्सटेंशन जो मुझे समझ में नहीं आता है - और मेरे लिए 'y foo'' y -> Foo * * x y z' जो आपको मिला है उसके बजाय है। यदि मैं एक फ़ंक्शन foo पेश करने का प्रयास करता हूं - आपने परिभाषा नहीं दी है, इसलिए मैंने "foo x y = foo y' - जीएचसी पैनिक्स" असंभव हुआ "के साथ प्रयास किया। – Cubic

0

यह प्रिंटिंग से संबंधित कुछ दुर्भाग्यपूर्ण कार्यान्वयन के कारण है। प्रकारों को 'प्रकार के प्रकार' के रूप में माना जा सकता है। नोट निम्नलिखित: "सभी प्रकार*, [*] के लिए", [*] का अर्थ है "सभी प्रकार के एक, [a] के लिए"

>:t [] 
[] :: [a] 
>:k '[] 
'[] :: [*] 

बस [a] की तरह साधन। हालांकि, आप तर्क के साथ प्रकार के साथ तर्क कर सकते हैं कि प्रकार के मुकाबले बहुत छोटा है। उदाहरण के लिए, a -> a इंगित करता है कि a एस एक ही प्रकार के हैं, लेकिन * -> * का अर्थ है * कोई भी प्रकार हो सकता है (इसे * -> * के रूप में सोचा जा सकता है a -> b प्रकार स्तर पर "उठाया गया") है। लेकिन a -> a टाइप प्रकार को उठाने का कोई तरीका नहीं है। इसका मतलब है कि [a] और [*] काफी समान नहीं हैं। [*][forall a . a] जैसे कुछ के करीब है। अधिक तेज़, लेकिन कम सटीक, आप कह सकते हैं कि 'पॉलिमॉर्फिक' प्रकारों को अलग करने का कोई तरीका नहीं है क्योंकि 'दयालु चर' जैसी कोई चीज़ नहीं है। (ओर ध्यान दें: -XPolyKinds सक्षम बनाता है क्या प्रलेखन कॉल 'बहुरूपी प्रकार', लेकिन यह अभी भी आप सच बहुरूपता नहीं देता है)

तो जब आप HList :: [*] -> * बारे में (जो वास्तव में HList (k :: [*]) :: * का मतलब है) आप संकेत कर रहे हैं कि पहले की तरह प्रकार पैरामीटर [*] होना चाहिए, और 'मान' उस तरह [*] के प्रकार ले जा सकते हैं '[], * ': '[], * ': * ': '[], आदि

अब समस्या है। जिन चीजों को मुद्रित किया गया है, उन्हें मुद्रित करते समय, HNil के पहले प्रकार पैरामीटर की तरह, यह सभी प्रकार की जानकारी शामिल करने का प्रयास करेगा। जो भी कारण, बजाय

HNil :: HList ('[] :: '[*]) 
^ data  ^type ^kind 

जो वास्तव में संकेत मिलता है कि *'[] की तरह करने के लिए बात कर रहा है लिखने के लिए, यह बेतहाशा भ्रामक प्रारूप आप देखा है में चीजों को प्रिंट करता है। यह जानकारी रखना जरूरी है, क्योंकि सूची के अंदर 'संग्रहीत' चीज की तरह खुली-तरह की आवश्यकता नहीं है (जो * का नाम है)। आपके पास कुछ ऐसा हो सकता है:

data Letter = A | B -- | C .. etc 
data LetterProxy p 

data HList (k :: [Letter]) where 
    HNil :: HList '[] 
    (:+:) :: LetterProxy (a :: Letter) -> HList t -> HList (a ': t) 

जो बेहद बेवकूफ है लेकिन अभी भी मान्य है!

मुझे विश्वास है कि यह गलतफहमी दो कारणों से है। सबसे पहले, अगर मैंने कहा प्रारूप में चीजें मुद्रित की गई हैं, तो कुछ डेटा प्रकारों या कक्षाओं के लिए :i का परिणाम बहुत लंबा और बहुत पढ़ा जा सकता है। दूसरा, प्रकार बहुत नए हैं (केवल 7.4 के बाद से?) इसलिए दयालु चीजों को मुद्रित करने का निर्णय लेने पर बहुत समय नहीं लगाया गया है, क्योंकि कोई भी अभी तक निश्चित नहीं है कि कैसे काम करना चाहिए/काम करना चाहिए।

+1

एर, मुझे लगता है कि आप थोड़ा सा कह रहे हैं कि '* -> *' प्रकार 'a -> b' जैसा है। यह कहना अधिक सटीक है कि यह 'Int -> Int' प्रकार जैसा है। '*' एक ठोस प्रकार है, एक प्रकार का चर नहीं। जैसे 'Int -> Int' मानों पर पहचान परिवर्तन को मजबूर नहीं करता है, '* -> *' प्रकारों पर पहचान परिवर्तन को मजबूर नहीं करता है। – Carl

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