對圖的映射似乎不是很正確的一種遍歷。以下內容適用於邊緣源節點的提取上下文。
edgeLookup :: Node -> [(a,Node)] -> Maybe ((a,Node), [(a,Node)])
edgeLookup n = aux . break ((== n) . snd)
where aux (h, []) = Nothing
aux (h, t:ts) = Just (t, h ++ ts)
incrementEdge :: Edge -> Gr a Int -> Maybe (Gr a Int)
incrementEdge (from,to) g = aux $ match from g
where aux (Nothing, _) = Nothing
aux (Just (i,n,l,o), g') = Just $ (i,n,l,checkEdge o) & g'
checkEdge outEdges =
maybe ((1,to):outEdges) incEdge $ edgeLookup to outEdges
incEdge ((cnt,n), rst) = (cnt+1,n):rst
我可能還使用一個輔助的(Maybe a, b) -> Maybe (a,b)
然後fmap aux
走過去與match
組成的幫手。這將有助於提煉出更好的東西。
EDIT
要基於標籤的支持節點此外,一個需要跟蹤標籤和節點標識符(整數)之間的雙射。這可以通過使用與圖形並行更新的Map
來完成。
import Data.Graph.Inductive
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe (fromJust)
-- A graph with uniquely labeled nodes.
type LGraph a b = (Map a Int, Gr a b)
-- Ensure that a node with the given label is present in the given
-- 'LGraph'. Return the Node identifier for the node, and a graph that
-- includes the node.
addNode :: Ord a => a -> LGraph a b -> (Int, LGraph a b)
addNode label (m,g) = aux $ M.lookup label m
where aux (Just nid) = (nid, (m,g))
aux Nothing = (nid', (m', g'))
[nid'] = newNodes 1 g
m' = M.insert label nid' m
g' = insNode (nid', label) g
-- Adding a context to a graph requires updating the label map.
(&^) :: Ord a => Context a b -> LGraph a b -> LGraph a b
[email protected](_, n, label, _) &^ (m,g) = (m', g')
where m' = M.insert label n m
g' = c & g
-- Look for a particular 'Node' in an edge list.
edgeLookup :: Node -> [(a,Node)] -> Maybe ((a,Node), [(a,Node)])
edgeLookup n = aux . break ((== n) . snd)
where aux (h, []) = Nothing
aux (h, t:ts) = Just (t, h ++ ts)
-- Increment the edge between two nodes; create a new edge if needed.
incrementEdge :: Edge -> Gr a Int -> Maybe (Gr a Int)
incrementEdge (from,to) g = fmap aux $ liftMaybe (match from g)
where aux ((i,n,l,o), g') = (i,n,l,checkEdge o) & g'
checkEdge outEdges =
maybe ((1,to):outEdges) incEdge $ edgeLookup to outEdges
incEdge ((cnt,n), rst) = (cnt+1,n):rst
liftMaybe :: (Maybe a, b) -> Maybe (a, b)
liftMaybe (Nothing, _) = Nothing
liftMaybe (Just x, y) = Just (x, y)
-- Increment an edge in an 'LGraph'. If the nodes are not part of the
-- graph, add them.
incrementLEdge :: Ord a => (a, a) -> LGraph a Int -> LGraph a Int
incrementLEdge (from,to) g = (m', fromJust $ incrementEdge' (from',to') g')
where (from', gTmp) = addNode from g
(to', (m',g')) = addNode to gTmp
-- Example
a' :: LGraph String Int
a' = ([],1,"a",[]) &^ (M.empty, empty)
b' = ([],2,"b",[]) &^ a'
test6 = incrementLEdge ("c","b") $ incrementLEdge ("b","a") b'
{-
*Main> test6
(fromList [("a",1),("b",2),("c",3)],
1:"a"->[]
2:"b"->[(1,1)]
3:"c"->[(1,2)])
-}
您的編輯與原始界面不匹配。在下面的答案中提供了原始問題的兩個工作版本,但是如果您還想向圖中添加新節點,那麼'incrementEdge'必須爲標籤以及所涉及節點的標識符。這聽起來像是在轉向混合節點標籤和節點標識符。如果您希望標籤是唯一的,則可以在供應單體中執行此操作。或者,您可以預留現在的「字符串」標籤,而只依賴整數節點標識符本身。 – Anthony 2010-10-12 15:48:01