2015-09-18 12 views
8

चलें मान मैं एक उदाहरण List के साथ एक प्रकार वर्ग Stack है:टाइप क्लास में एकाधिक प्रकार पैरामीटर?

class Stack a where 
    push :: a -> Integer -> a 
    pop :: a -> a 
    last :: a -> Integer 

data List = Empty | Element Integer List 
instance Stack List where 
    push list value = Element value list 
    pop Empty = error "No elements" 
    pop (Element _ list) = list 
    last Empty = error "No elements" 
    last (Element value _) = value 

कैसे List के क्रम में परिभाषित करने की Stack है Integer मूल्यों तक ही सीमित नहीं किया जाना है?

-- class Stack (?) where ... 
data List a = Empty | Element a (List a) 
-- instance Show (List a) where ... 

उत्तर

6

उस मामले में आप एक multiparameter वर्ग बना सकते हैं:

class Stack a b where 
    push :: a -> b -> a 
    pop :: a -> a 
    last :: a -> b 

और साथ इसे परिभाषित: है कि यह एक डिफ़ॉल्ट नहीं है

instance Stack (List b) b where --You don't need to use `b`, but this make it easier to understand 
    push list value = Element value list 
    pop Empty = error "No elements" 
    pop (Element _ list) = list 
    last Empty = error "No elements" 
    last (Element value _) = value 

नोट (मानकीकृत) हास्केल सुविधा, और कि आपको इसे चालू करने की आवश्यकता होगी। या तो संकलक को -XMultiParamTypeClasses और -XFlexibleInstances पास करके।

या आप लिख सकते हैं:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} 
अपने स्रोत फ़ाइल के शीर्षक में


ध्यान दें कि वहाँ एक a जिसके लिए आप एक उदाहरण (और इसके विपरीत) को परिभाषित करने के लिए कई b के हो सकता है। इससे इस तरह के वर्गों के साथ काम करना मुश्किल हो सकता है। उदाहरण के लिए मान लीजिए कि आप एक Dummy प्रकार लिखें:

data Dummy = Dummy 

आप को परिभाषित कर सकते हैं:

instance Stack Dummy b where 
    push x = const x 
    pop = id 
    last = const $ error "Dummy object" 

अब यह मतलब है कि आप हर संभव b के लिए Stack उदाहरण है, ताकि आप कर सकते हैं push और pop के सभी प्रकार Dummy वस्तुओं के लिए सामान।

+1

इससे पहले मैंने वास्तव में एक ही वाक्यविन्यास की कोशिश की, लेकिन केवल 'इंस्टेंस स्टैक (सूची ए) लिखा। और मैं प्रज्ञा के लिए 'फ्लेक्सिबल इंस्टेंस' को जोड़ना भूल गया। अब यह काम करता है, धन्यवाद :) – Cubinator73

+0

यदि प्रत्येक 'ए' एक 'बी' पर स्वीकार करता है जैसे कि 'बीए स्टैक' का एक उदाहरण है, तो एक कार्यात्मक निर्भरता 'ए-> बी' टाइप अनुमान मशीनरी को महत्वपूर्ण रूप से मदद कर सकती है। अन्यथा, 'pop :: a -> a' पर प्रत्येक कॉल संदिग्ध है: 'b'' pop' के संदर्भ से निर्धारित नहीं किया जा सकता है। (निश्चित रूप से परिवारों का भी इस्तेमाल किया जा सकता है।) – chi

+0

@chi: आईआईआरसी आप प्रतिबंध जोड़ सकते हैं, जैसे कि 'ए' के ​​लिए केवल एक ही 'बी' होगा। बाद में इसे देखेंगे। –

8

एक उच्च श्रेणी वाले वर्ग चर का उपयोग करने पर विचार करें। इस प्रकार:

class Stack s where 
    push :: s a -> a -> s a 
    pop :: s a -> s a 
    last :: s a -> a 

data List a = Empty | Element a (List a) 

उदाहरण बनी हुई है बिल्कुल के रूप में आप इसे लिखा था (हालांकि List अब तरह * -> ** के बजाय है):

instance Stack List where 
    push list value = Element value list 
    pop Empty = error "No elements" 
    pop (Element _ list) = list 
    last Empty = error "No elements" 
    last (Element value _) = value 

यह दृष्टिकोण शुद्ध है हास्केल 2010 - यह कोई एक्सटेंशन की आवश्यकता है।

इसके अलावा, अपनी असफलताओं को देखने योग्य बनाने पर विचार करें; उदाहरण के लिए क्रमशः Maybe (s a) और Maybe a वापस करने के लिए pop और last के प्रकार को बदलकर।

+0

यह मेरे लिए एक महान दृष्टिकोण की तरह दिखता है। और मैं निश्चित रूप से 'शायद' कोशिश कर रहा हूं :) – Cubinator73

+0

@ क्यूबिनेटर 73 यह आमतौर पर * जाने का तरीका है। एक कार्यात्मक निर्भरता (या एक संबंधित पैरामीटर के साथ एक एकल पैरामीटर टाइपक्लास) के साथ मल्टीपार्माटर टाइपक्लास दृष्टिकोण समझ में आता है यदि आप एकाधिक मोनोमोर्फिक स्टैक प्रकारों पर विचार कर रहे हैं। – dfeuer

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