2013-02-13 17 views
5

हम तरह * के पैरामीटर के लिए एकल, व्यापक उदाहरणों लिख सकते हैं:पैटर्न पर मिलान प्रचारित प्रकार

class MyClass d where 
    f :: d -> Int 

instance MyClass (Maybe d) where 
    f _ = 3 

test1 :: Maybe d -> Int 
test1 x = f x 

यह ठीक संकलित, और ध्यान दें कि हम एक (MyClass (हो सकता है कि घ)) ज़रूरत नहीं है पर रोके test1 क्योंकि कंपाइलर किसी भी Maybe d के लिए मिलान करने वाला उदाहरण पाता है।

हम भी वर्ग पैरामीटर प्रकार निर्माता ये हैं के लिए एक अखिल उदाहरण लिख सकते हैं:,

class MyClass2 (a :: * -> *) where 
    g :: Tagged (a Int) Int 

instance MyClass2 a where 
    g = Tagged 3 

test2 :: Int 
test2 = untag (g :: Tagged (Maybe Int) Int) 

यह भी ठीक संकलित, और test2 एक (MyClass2 शायद) बाधा की जरूरत नहीं है क्योंकि संकलक एक पाता है मिलान उदाहरण

{-# LANGUAGE TypeOperators, 
DataKinds, 
KindSignatures, 
GADTs, 
FlexibleInstances, 
FlexibleContexts, 
ScopedTypeVariables #-} 

import Data.Tagged 
import Data.Proxy 

data HList :: [*] -> * where 
       HNil :: HList '[] 
       HCons :: a -> HList as -> HList (a ': as) 

class ListLen a where 
    len :: Tagged a Int 

instance ListLen (HList '[]) where 
    len = Tagged 0 

instance (ListLen (HList as)) => ListLen (HList (a ': as)) where 
    len = Tagged (1+(untag (len :: Tagged (HList as) Int))) 

test3 :: Int 
test3 = untag (len :: Tagged (HList '[Int, Double, Integer]) Int) 

test4 :: (Proxy (HList qs)) -> Int 
test4 (_ :: Proxy (HList qs)) = untag (len :: Tagged (HList qs) Int) -- error occurs here 

यह त्रुटि में परिणाम है:

निम्नलिखित खिलौना कोड एक (पदोन्नत) की लंबाई की गणना सूची टाइप करने के लिए विचार करें

No instance for (ListLen (HList qs)) 
     arising from a use of `len' 
    Possible fix: add an instance declaration for (ListLen (HList qs)) 
    ... 

हम test4 के लिए हस्ताक्षर बाहर टिप्पणी करते हैं, तो जीएचसीआई

test4 :: (ListLen (HList qs)) => (Proxy (HList qs)) -> Int 

पर टाइप करता है लेकिन यह आवश्यक नहीं होना चाहिए। जाहिर है, मैंने ListLen के लिए उदाहरण लिखे हैं जो किसी भी कल्पनीय प्रकार की सूची से मेल खाते हैं: एक 'खाली सूची' केस, और 'विपक्ष' केस। अगर मैं ListLen पैरामीटर को [*] (यानी HList रैपर ListLen और उसके उदाहरणों में हटा दें) को बदलने के लिए ListLen पैरामीटर को बदलता हूं तो समस्या वही बना रहता है।

हम test4, test3 compiles बाहर टिप्पणी और ठीक चलाता है: के बाद से मैं (अनिवार्य) यह मैं कैसे निर्माण प्रकार सूची के लिए स्पष्ट वाक्य रचना ('[Int,Double,Integer]) दे दी है, संकलक मिलान उदाहरणों को खोजने के लिए सक्षम था।

मैं कोड लिखने का प्रयास कर रहा हूं जो मेरे लिए एक प्रकार की सूची बनाता है, इसलिए मुझे स्पष्ट प्रकार की सूची वाक्यविन्यास लिखना नहीं होगा। हालांकि, ऐसा लगता है कि स्पष्ट वाक्यविन्यास का उपयोग करना एकमात्र तरीका है जीएचसी इन व्यापक उदाहरणों से मेल खाता है। शायद एक मामला है जो मुझे याद आ रही है? सिंटेक्स मैं उपयोग नहीं कर रहा हूँ?

जीएचसी को यह समझने के लिए मैं क्या कर सकता हूं कि मेरे पास [*] की तरह सब कुछ है? मैं जीएचसी 7.4.2 का उपयोग कर रहा हूं। यह गैर-प्रचारित प्रकारों को डीकनस्ट्रक्चर करने के बारे में previous post से संबंधित हो सकता है। प्रकार के प्रचार पर पेपर here पाया जा सकता है।

+0

शीर्षक सुझावों का स्वागत है। – crockeea

+0

आपके पास * अलग * उदाहरण हैं, यह कोई नहीं होगा? जीएचसी को उदाहरण चुनना है, और यह एक गैर-पैरामीट्रिक ऑपरेशन है, इसलिए एक बाधा की आवश्यकता है। मुझे नहीं लगता कि आप क्या करना चाहते हैं समझ में आता है। –

+0

जीएचसी एक स्पष्ट वर्ग बाधा का उपयोग कर रनटाइम पर * ओवरलैपिंग * उदाहरण (जो ये नहीं हैं) को हल भी कर सकता है (जो अन्यथा अनुमानित होगा)। यह क्यों नहीं देख सकता कि हमेशा * एक मैच होता है, भले ही इसे उचित उदाहरण चुनने के लिए रनटाइम तक इंतजार करना पड़े? बेशक, मैं इसे * बिना * स्पष्ट (और gratuitous) वर्ग की बाधा के लिए करने के लिए कह रहा हूं, जिसमें मेरे पास प्रदान करने की लक्जरी नहीं है। – crockeea

उत्तर

2

यह वही नहीं है जो आप चाहते हैं, लेकिन बहुत करीब हो जाता है।मैं

data Proxy a where 
    Proxy :: ListLen a => Proxy 
तो

data Proxy a where 
    Proxy :: Tagged a Int -> Proxy a 

साथ बाहर शुरू कर दिया

test4 :: (Proxy (HList qs)) -> Int 
test4 (Proxy len) = untag len 

में जिसके परिणामस्वरूप समस्या आप या तो आवश्यक वर्ग के सबूत भी होते हैं (बाधा है, या Proxy की आवश्यकता है हालांकि सभी उपलब्ध प्रकारों के लिए उदाहरण मौजूद हैं)। यहां, कक्षा विधि सिर्फ Proxy में शामिल है।

एक बिल्कुल अलग विकल्प है कि केवल एक प्रकार का वर्ग न उपयोग करें, और len को सामान्य तरीके से कार्यान्वित करें (Data.List.length से लिखित)।

len :: HList a -> Int 
len l = len' l 0 
    where 
    len' :: HList a -> Int -> Int 
    len' HNil a = a 
    len' (HCons _ xs) a = len' xs $! a + 1 
संबंधित मुद्दे