2009-11-05 22 views
22

एक C++ प्रोग्रामर हास्केल यहाँ जानने की कोशिश कर हास्केल में एक डेटा संरचना का विस्तार करने के। कृपया इस संभव सवाल को क्षमा करें। मैं एक ऐसे प्रोग्राम का अनुवाद करना चाहता हूं जो 3 डी आकार का प्रतिनिधित्व करता हो।विरासत

class Shape { 
public: 
    std::string name; 
    Vector3d position; 
}; 

class Sphere : public Shape { 
public: 
    float radius; 
}; 

class Prism : public Shape { 
public: 
    float width, height, depth; 
}; 

मैं (रिकॉर्ड का उपयोग कर?) इतना है कि मैं कुछ कार्य करता है जो पता है (जैसा कि इसके नाम और स्थिति तक पहुँचने की तरह) एक आकार पर काम करने के लिए कैसे हो सकता है हास्केल को यह अनुवाद करने के लिए कोशिश कर रहा हूँ: C++ में मैं की तरह कुछ है , और दूसरों को केवल गोलाकारों पर कैसे काम करना है, इसकी स्थिति और त्रिज्या के आधार पर कुछ की गणना करना।

सी में एक सदस्य समारोह सिर्फ इन मानकों का उपयोग कर सकता है लेकिन मैं एक मुश्किल समय पता लगाना कैसे रिकॉर्ड, या प्रकार कक्षाएं, या जो कुछ भी साथ हास्केल में यह करने के लिए आ रही हैं ++।

धन्यवाद।

उत्तर

13

टाइपक्लास के उपयोग को हतोत्साहित करने की प्रवृत्ति के विपरीत, मैं विभिन्न दृष्टिकोणों के विभिन्न व्यापारिक तरीकों के लिए एक महसूस करने के लिए टाइपक्लास और एक के बिना समाधान दोनों का पता लगाने की सलाह दूंगा (जैसा कि आप सीख रहे हैं)।

"एकल बंद डेटाटाइप" समाधान निश्चित रूप से टाइपक्लास से अधिक "कार्यात्मक" है। इसका तात्पर्य है कि आकारों की आपकी सूची आपके आकार मॉड्यूल द्वारा "निश्चित" है और बाहर से नए आकार के साथ एक्स्टेंसिबल नहीं है। आकृतियों पर चल रहे नए कार्यों को जोड़ना अभी भी आसान है।

यदि आपके पास कोई ऐसा फ़ंक्शन है जो केवल एक ही आकार के प्रकार पर चल रहा है, तो आपके पास थोड़ी सी असुविधा होती है क्योंकि आप स्थैतिक कंपाइलर चेक छोड़ देते हैं कि फ़ंक्शन के लिए पारित आकार सही है (नाथन का उदाहरण देखें)। यदि आपके पास इनमें से बहुत से आंशिक कार्य हैं जो केवल आपके डेटाटाइप के एक कन्स्ट्रक्टर पर काम करते हैं, तो मैं दृष्टिकोण पर पुनर्विचार करता हूं।

एक typeclass समाधान के लिए, मैं व्यक्तिगत रूप से नहीं बल्कि नहीं आकार वर्ग पदानुक्रम, दर्पण लेकिन, "एक त्रिज्या के साथ बातें" "एक मात्रा के साथ बातें" "एक सतह क्षेत्र के साथ बातें" के लिए प्रकार कक्षाएं बनाने चाहते हैं। ..

यह आपको उन कार्यों को लिखने की अनुमति देता है जो विशेष प्रकार के आकार लेते हैं, गोलाकार कहते हैं, केवल (जैसा कि प्रत्येक आकार का अपना प्रकार है), लेकिन आप एक ऐसा फ़ंक्शन नहीं लिख सकते जो "कोई आकार" लेता है और फिर अंतर करता है आकार के विभिन्न ठोस प्रकार।

20

सीधी-सपाट अनुवाद।

type Vector3D = (Double, Double, Double) 

class Shape shape where 
    name :: shape -> String 
    position :: shape -> Vector3D 

data Sphere = Sphere { 
    sphereName :: String, 
    spherePosition :: Vector3D, 
    sphereRadius :: Double 
} 

data Prism = Prism { 
    prismName :: String, 
    prismPosition :: Vector3D, 
    prismDimensions :: Vector3D 
} 

instance Shape Sphere where 
    name = sphereName 
    position = spherePosition 

instance Shape Prism where 
    name = prismName 
    position = prismPosition 

हालांकि आप आमतौर पर ऐसा नहीं करेंगे; यह दोहरावदार और बहुलक सूची में भाषा एक्सटेंशन की आवश्यकता है।

इसके बजाय, उन्हें एक ही बंद डेटाप्रकार में चिपके हुए शायद पहली समाधान आप के लिए जाना चाहिए।

type Vector3D = (Double, Double, Double) 

data Shape 
    = Sphere { name :: String, position :: Vector3D, radius :: Double } 
    | Prism { name :: String, position :: Vector3D, dimensions :: Vector3D } 

आप निश्चित रूप से अधिक typeclasses बनाने के द्वारा विरासत के कई स्तरों अनुकरण कर सकते हैं:

class (Shape shape) => Prism shape where 
    dimensions :: Vector3D 
data RectangularPrism = ... 
data TriangularPrism = ... 
instance Prism RectangularPrism where ... 
instance Prism TriangularPrism where ... 

तुम भी डेटाटाइप्स एम्बेड करके यह अनुकरण कर सकते हैं।

type Vector3D = (Double, Double, Double) 

data Shape = Shape { name :: String, position :: Vector3D } 

data Sphere = Sphere { sphereToShape :: Shape, radius :: Double } 
newSphere :: Vector3D -> Double -> Shape 
newSphere = Sphere . Shape "Sphere" 

data Prism = Prism { prismToShape :: Shape, dimensions :: Vector3D } 

data RectangularPrism = RectangularPrism { rectangularPrismToPrism :: Prism } 
newRectangularPrism :: Vector3D -> Vector3D -> RectangularPrism 
newRectangularPrism = (.) RectangularPrism . Prism . Shape "RectangularPrism" 

data TriangularPrism = TriangularPrism { triangularPrismToPrism :: Prism } 
newTriangularPrism :: Vector3D -> Vector3D -> TriangularPrism 
newTriangularPrism = (.) TriangularPrism . Prism . Shape "TriangularPrism" 

लेकिन हास्केल में OO अनुकरण के पास कहीं भी नहीं है वास्तव में एक Haskellish तरह से सोच के रूप में के रूप में संतोषजनक। तुम क्या करने की कोशिश कर रहे हो?

(भी ध्यान रखें कि इन समाधानों में से सब केवल upcasts की अनुमति, downcasting असुरक्षित और उसे अस्वीकृत है।)

+2

आप एक विरासत श्रृंखला का प्रतिनिधित्व कैसे करेंगे जो एक से अधिक स्तर गहरे हैं? जैसे 'आकार' -> 'प्रिज्म' -> 'आयताकारप्रिज्म' – barkmadley

2

एक साधारण अनुवाद बात यह है कि भिन्न होता है लेकिन typeclasses से बचा जाता है बाहर टूटता है:

type Vector3D = (Float,Float,Float) 
data Body = Prism Vector3D | Sphere Double 
radius (Prism position) = -- code here 
radius (Sphere r) = r 

तो

data Shape = Shape { 
    name :: String, 
    position :: Vector3D, 
    body :: Body 
} 

shapeOnly (Shape _ pos _) = -- code here 

both = radius . body 

sphereOnly (Shape _ _ (Sphere radius)) = -- code here 
sphereOnly _ = error "Not a sphere" 

यह नहीं एक वास्तव में आसान सवाल है। सी ++ और हास्केल के बीच डेटा संरचना डिजाइन बहुत अलग है, इसलिए मैं शर्त लगाता हूं कि ओओ भाषा से आने वाले ज्यादातर लोग एक ही बात पूछते हैं। दुर्भाग्य से, सीखने का सबसे अच्छा तरीका है; आपकी सबसे अच्छी शर्त यह है कि जब तक आप सीखें कि हास्केल में चीजें कैसे काम करती हैं, तब तक केस-दर-मामले आधार पर इसे आजमाएं।

मेरा जवाब बहुत सरल है, लेकिन यह इस मामले में जहां एक भी सी ++ उपवर्ग तरीकों कि दूसरों को नहीं है के साथ अच्छी तरह से निपटने के नहीं है। यह रनटाइम त्रुटि फेंकता है और बूट करने के लिए अतिरिक्त कोड की आवश्यकता होती है। आपको यह भी तय करना होगा कि "सबक्लास" मॉड्यूल निर्णय लेता है कि त्रुटि या "सुपरक्लास" मॉड्यूल को फेंकना है या नहीं।

6

नाथन की तरह कहा, डेटाटाइप्स मॉडलिंग सी से हास्केल में पूरी तरह से अलग है ++।आप निम्न दृष्टिकोण पर विचार कर सकते हैं:

data Shape = Shape { name  :: String, position :: Vector3d } 
data Sphere = Sphere { sphereShape :: Shape, radius :: Float } 
data Prism = Prism { prismShape :: Shape, width :: Float, height :: Float, depth :: Float } 

दूसरे शब्दों में, सुपर डेटा के मॉडल को आपके डेटाटाइप में अतिरिक्त फ़ील्ड के रूप में संदर्भित करता है। यह आसानी से लंबी विरासत श्रृंखला तक फैलता है।

टाइप क्लास का उपयोग न करें, जैसे महाकाव्य सुझाव। इन्हें ओवरलोडिंग कार्यों के लिए उपयोग किया जाता है और यह यहां कोई मुद्दा नहीं है: आपका प्रश्न डेटा के मॉडलिंग से संबंधित है, व्यवहार नहीं।

आशा है कि इससे मदद मिलती है!

+0

क्या आप सुझाव देते हैं कि डेटा विरासत मॉडलिंग करते समय, अतिरिक्त फ़ील्ड का उपयोग करें, जब व्यवहार विरासत मॉडलिंग करते हैं, प्रकार वर्गों का उपयोग करें। अन्य प्रकार के वर्गों पर कक्षा पैरामीटर टाइप कर सकते हैं? – CMCDragonkai

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