2011-06-07 7 views
5

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

data Node = Node { label :: Char 
       , index :: Int 
       } deriving (Ord, Eq) 
type Graph edgeType = ([Node], [edgeType]) 
data Edge = DirectedEdge {h :: Node, t :: Node} 
      | UndirectedEdge {a :: Node, b :: Node} 
instance Show Node where 
    show n = ['(', label n, ')'] 
instance Show Edge where 
    show (DirectedEdge h t) = show h ++ "->" ++ show t 
    show (UndirectedEdge a b) = show a ++ "-" ++ show b 

तो मैं निर्देशित और अनिर्दिष्ट किनारों के बीच भेद कर रहा हूँ है। एक ग्राफ में केवल किसी भी प्रकार के किनारों का होना चाहिए। ,

nodes :: [Node] 
nodes = zipWith Node ['a'..] [0..] 

emptyGraph :: [Node] -> Graph edgeType 
emptyGraph ns = (ns, []) 

अब तक तो अच्छा है लेकिन मैं एक समारोह connect लिख रहा हूँ, एक मौजूदा ग्राफ एक नोड जोड़ता है के साथ: मैं भी निम्न है। आदर्श रूप में, मैं केवल इसे अप्रत्यक्ष ग्राफ पर लागू करना चाहता हूं, लेकिन यह एक विकल्प प्रतीत नहीं होता है। इसके बजाय, मैं कुछ इस तरह है:

connect :: Graph edgeType -> Node -> Graph edgeType 
connect (ns, es) n = (n:ns, e:es) 
    where e = UndirectedEdge n (head ns) 

लेकिन यह निम्न त्रुटि देता है:

Couldn't match type `edgeType' with `Edge' 
    `edgeType' is a rigid type variable bound by 
      the type signature for 
       connect :: Graph edgeType -> Node -> Graph edgeType 

सबसे अच्छा तरीका है पूरा करने के लिए मैं क्या हासिल करने की कोशिश कर रहा हूँ क्या है?

उत्तर

7

आप शायद दो अलग-अलग बढ़त के बजाय प्रकार Edge

करना चाहते हैं
newtype DirectedEdge = DirectedEdge { h :: Node, t :: Node} 
newtype UndirectedEdge = UndirectedEdge { a :: Node, b :: Node} 

और तुम शायद यह है कि आप वापस एक (Node, Node) देता है एक मनमाना धार दी typeclass किसी तरह हैं:

+०१२३५१६४१०
class HasNodeEndpoints a where 
    endpoints :: a -> (Node, Node) 

-- obvious instances for DirectedEdge and UndirectedEdge 

फिर जब आप मनमाने ढंग से ग्राफ के बारे में बात करना चाहते हैं, तो आप Graph a पर काम करने वाले कार्यों को लिखेंगे, और शायद HasNodeEndpoints a => Graph a पर काम करेंगे। ग्राफ प्रकार के बारे में परवाह करने वाले एल्गोरिदम क्रमशः निर्देशित और अप्रत्यक्ष ग्राफ के लिए Graph DirectedEdge और Graph UndirectedEdge पर काम करेंगे।

एक और प्राकृतिक विस्तार निर्देशित और अप्रत्यक्ष किनारों को लेबल किया जाएगा।

class HasLabeled a where 
    type Label a -- associated type synonym 
    label :: a -> Label a 
    updateLabel :: a -> (Label a -> Label a) -> a 

-- now define data types and instances for labeled directed and undirected edges 
1

क्योंकि आप का उपयोग करते समय एक विशिष्ट किनारे प्रकार, Edge चुनते हैं, तो परिणाम यह है कि आपका ग्राफ किनारे के प्रकार में बहुलक नहीं है। यह प्रकार है करने के लिए है:

connect :: Graph Edge -> Node -> Graph Edge 
connect (ns, es) n = (n:ns, e:es) 
    where e = UndirectedEdge n (head ns) 

वहाँ के बाद से noo अन्य प्रकार अपने किनारों हो सकता है, कि UndirectedEdge का स्पष्ट उपयोग दिया।


एक के रूप में अलग रूप में, मैं, नोड्स पर कड़ाई एनोटेशन का उपयोग होता है सिर्फ अच्छे स्वास्थ्य की बात के रूप:

data Node = Node { label :: !Char 
       , index :: !Int 
       } deriving (Ord, Eq) 
+0

धन्यवाद। क्या कोई तरीका है कि मैं 'गठबंधन' _only_ अप्रत्यक्ष ग्राफ पर लागू कर सकता हूं जैसा कि मैंने उन्हें परिभाषित किया है? 'कनेक्ट :: ग्राफ अप्रत्यक्ष एज -> नोड -> ग्राफ अप्रत्यक्ष एज' काम नहीं करता है। –

+0

@ जोर्डन यह काम नहीं करता है क्योंकि 'अप्रत्यक्ष एज' एक "कन्स्ट्रक्टर" है और "टाइप" नहीं है। आपको लैम्बेडेक के सुझावों के साथ एक समाधान को देखने की ज़रूरत है, एज को दो अलग-अलग प्रकारों में विभाजित करना है। –

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

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