这是有问题的代码(也在lpaste.net上):
module Data.Graph.Dijkstra ( dijkstra , dijkstraPath ) where -- Graph library import import Data.Graph.Inductive hiding (dijkstra) -- Priority queue import import qualified Data.PQueue.Prio.Min as PQ -- Standard imports import Data.List (find) import Data.Maybe (fromJust) import Data.Monoid -- Internal routine implementing Dijkstra's shortest paths -- algorithm. Deemed internal because it needs to be kickstarted with -- a singleton node queue. Based on FGL's current implementation of -- Dijkstra. dijkstraInternal :: (Graph gr, Ord b, Monoid b) => gr a b -> PQ.MinPQueue b [Node] -> [[Node]] dijkstraInternal g q | PQ.null q = [] | otherwise = case match v g of (Just cxt,g') -> p:dijkstraInternal g' (PQ.unions (q' : expand cxt minDist p)) (Nothing, g') -> dijkstraInternal g' q' where ((minDist,p@(v:_)), q') = PQ.deleteFindMin q expand (_,_,_,s) dist pathToC = map (\(edgeCost,n) -> PQ.singleton (dist `mappend` edgeCost) (n:pathToC)) s -- Given a graph and a start node, returns a list of lists of nodes -- corresponding to the shortest paths from the start to all other -- nodes, where the edge costs are accumulated according to the Monoid -- instance of the edge label type and costs are compared by the edge -- label's Ord instance. dijkstra :: (Graph gr, Ord b, Monoid b) => gr a b -> Node -> [[Node]] dijkstra g start = dijkstraInternal g (PQ.singleton `mempty` [start]) -- !!! dijkstraPath :: (Graph gr, Ord b, Monoid b) => gr a b -> Node -> Node -> [LNode a] dijkstraPath g start goal = let paths = dijkstra g start pathNodes = find ((goal ==) . head) paths -- Can paths be empty? in case pathNodes of Nothing -> [] Just ps -> reverse $ map (\n -> (n, fromJust $ lab g n)) ps
奇怪的是在第39行,标有-- !!!
评论.此代码编译,但运行时错误是无论如何,该PQ.singleton
函数返回一个空的优先级队列.我意识到我不小心添加了反引号mempty
,所以当我删除那些代码编译并按预期工作时.
然而这让我感到奇怪.如何用反引号正确编译代码mempty
,这根本不是二进制函数(mempty :: a
)?
在对#haskell提供了一些非常慷慨的帮助之后,我发现它与函数的Monoid实例有关:
instance Monoid b => Monoid (a -> b)
我现在非常模糊地理解为什么这个错误成功地进行了类型检查,但我仍然觉得在某种程度上受到了道德冤枉.有人能解释这是怎么发生的吗?
另外,我还想关注singleton
我正在使用的优先级队列的功能:根据源,它不返回空队列.但是,在第24行,相同的优先级队列立即被评估为空.(我通过跟踪调用验证了这一点.)