2012-02-15 18 views
10

मेरे पास ऐसे कार्यों का एक समूह है जो वेक्टरों पर काम करते हैं, यानी टाइप-लागू लंबाई के साथ सूचियां।पैरामीटरयुक्त प्रकार समानार्थी शब्द

मैं तो मैं बस लिख सकते हैं foo :: NList v Integer => ...

(सरलीकृत) वर्ग

foo :: (Fold Integer v, Map Integer Integer v v, ...) => ... 

मैं एक नया वर्ग NList की घोषणा कर रहा हूँ लेखन लिखने के लिए मेरी प्रकार आसान बनाने के लिए कोशिश कर रहा हूँ, यानी बजाय

class (Fold (v i) i 
     , Map i i (v i) (v i) 
     , Map i (Maybe i) (v i) (v (Maybe i)) 
    ) => NList v i 

आप देख सकते हैं, मैं "वेक्टर" प्रकार ("आइटम" प्रकार से अलग रखना है यानी: इस तरह दिखता हैi से अलग) ताकि मैं Map जैसी चीजें Maybe वेक्टर पर कर सकूं।

ऐसे में, v में * -> *, और i दयालु * होना चाहिए।

हालांकि, जब मैं बहुत तरह वैक्टर के साथ यह दृष्टांत का प्रयास करें:

instance NList Vec2 Integer 
instance NList Vec3 Integer 
... 

मैं निम्नलिखित त्रुटि मिलती है:

Type synonym `Vec2' should have 1 argument, but has been given none 
In the instance declaration for `NList Vec2 Integer' 

अब, मैं बहुत टाइप स्तर के प्रोग्रामिंग नया हूँ, और मैं समझता हूं कि मैं इसे बहुत पिछड़े फैशन में कर रहा हूं। क्या इस तरह के एक प्रकार के पर्याय को तुरंत चालू करना संभव है? क्या किसी भी प्रकार के जादूगरों के पास मेरे लक्ष्यों को पूरा करने के बेहतर तरीकों के लिए सुझाव हैं?

उत्तर

10

समस्या है कि यहाँ Vec2 और Vec3 शायद कुछ इस तरह के रूप में घोषित कर रहे हैं:

type Vec2 a = Vec (S (S Z)) a 
type Vec3 a = Vec (S (S (S Z))) a 

प्रकार समानार्थी शब्द आंशिक रूप से लागू किया जा सकता है, विभिन्न रहस्यमय कारणों के लिए (वे प्रकार स्तरीय lambdas, करने के लिए नेतृत्व करेंगे जो उदाहरण संकल्प और अनुमान से संबंधित सभी प्रकार की चीजों के साथ मलबे का विनाश - कल्पना करें कि क्या आप type Id a = a को परिभाषित कर सकते हैं और इसे Monad का उदाहरण बना सकते हैं)।

है कि कहने के लिए है, जैसे कि यह एक तरह * -> * साथ एक पूरी तरह कलियाना प्रकार निर्माता था आप Vec2 कुछ भी का एक उदाहरण नहीं कर सकते, क्योंकि आप Vec2 का उपयोग नहीं कर सकते हैं; यह प्रभावी रूप से एक प्रकार-स्तर "मैक्रो" है जिसे केवल पूरी तरह से लागू किया जा सकता है।

हालांकि, अगर आप प्रकार समानार्थी शब्द आंशिक अनुप्रयोगों के रूप में परिभाषित कर सकते हैं खुद को:

type Vec2 = Vec (S (S Z)) 
type Vec3 = Vec (S (S (S Z))) 

ये बराबर हैं, सिवाय इसके कि आपके उदाहरणों अनुमति दी जाएगी।

अपने Vec3 प्रकार वास्तव में की तरह

type Vec3 a = Cons a (Cons a (Cons a Nil))) 

या इसी तरह लग रहा है, तो आप भाग्य से बाहर हो; यदि आप किसी भी उदाहरण देना चाहते हैं तो आपको newtype रैपर का उपयोग करना होगा।(दूसरी ओर, आप पूरी तरह बजाय Nil और Cons के लिए उदाहरणों दे रही है, तो आप एक उदाहरण के रूप में Vec3 का उपयोग करने की अनुमति देकर उदाहरणों इन प्रकार पर सीधे परिभाषित करने से बचने के लिए सक्षम होना चाहिए।)

ध्यान दें कि GHC 7.4 के नए के साथ constraint kinds, तो आपको एक अलग प्रकार पूरी तरह से बच सकते हैं, और बस एक बाधा पर्याय निर्धारित करें:

type NList v i = 
    (Fold (v i) i 
    , Map i i (v i) (v i) 
    , Map i (Maybe i) (v i) (v (Maybe i)) 
    ) 

जहाँ तक सामान्य हो जाता है, यह मूल रूप से ठीक से काम करना चाहिए में अपने दृष्टिकोण के रूप में; उसी सामान्य विचार का उपयोग पैकेज द्वारा किया जाता है। कक्षाओं और बड़े संदर्भों की बड़ी संख्या में त्रुटि संदेश बहुत भ्रमित हो सकते हैं और संकलन धीमा कर सकते हैं, लेकिन टाइप-स्तरीय हैकरी की प्रकृति ऐसी है। हालांकि, अगर आप एक आधार Vec प्रकार सामान्य GADT के रूप में परिभाषित किया है:

data Vec n a where 
    Nil :: Vec Z a 
    Succ :: a -> Vec n a -> Vec (S n) a 

तो आप वास्तव में किसी भी typeclasses बिल्कुल जरूरत नहीं है। इसे किसी अन्य तरीके से परिभाषित किया है, लेकिन अभी भी एक प्रकार स्तरीय प्राकृतिक पर parametrised रहा है, तो आप एक साथ सभी वर्गों की जगह ले सकता:

data Proxy s = Proxy 

class Nat n where 
    natElim 
     :: ((n ~ Z) => r) 
     -> (forall m. (n ~ S m, Nat m) => Proxy m -> r) 
     -> Proxy n 
     -> r 

यह आपको संदर्भों को पूरी तरह खत्म करने के लिए अनुमति चाहिए, लेकिन आपरेशन को परिभाषित करता है वैक्टरों पर थोड़ा सा ट्रिकियर।

+0

बहुत अच्छा, धन्यवाद। एक चीज जो मुझे नहीं मिलती वह आखिरी उदाहरण है। टिल्ड ऑपरेटर के साथ क्या चल रहा है? – So8res

+0

यह एक [समानता बाधा] है (http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/equality-constraints.html)। यदि आपके पास गुंजाइश में 'संख्या' बाधा है, तो आप अंकगणित ऑपरेटरों का उपयोग 'ए' के मानों पर कर सकते हैं; यदि आपके पास दायरे में '(ए ~ बी) 'बाधा है, तो आप' ए' मानों का उपयोग' बी' मानों और इसके विपरीत के रूप में कर सकते हैं। असल में, आप '(एन ~ जेड) => आर' पढ़ सकते हैं "मुझे साबित करें कि' n' 'Z' है, और मैं आपको' आर' 'दूंगा। – ehird

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