我已经尝试根据下面的Dijkstra's algorithm在两个图形节点之间的最短距离上编写计算,但是我的代码中的两件事看起来相当迫切和乏味:
所以我想学习如何以更加惯用的方式来改善它Haskell
。非常感谢。
import qualified Data.Set as Set (size, insert)
import Data.Set (Set, empty, notMember)
import qualified Data.Map as Map (size, insert, lookup)
import Data.Map (Map, fromList)
import Data.Maybe (fromJust)
{-
g: Graph map, every edge weighs 1 for simplicity.
s: Source vertex
t: Target vertex
c: Current vertex
a: Adjacent vertex
as: Adjacent vertex list
v: Visited vertex set
d: Shortest distance map
-}
-- purposely skipped explicit type signature to make it short below,
calToTarget g t c v d
| Set.size v < Map.size g - 1
&& c /= t
&& notMember c v
= calFromAdj (lookup' c g) g t c v d
| otherwise = d
calFromAdj [] _ _ _ _ d = d
calFromAdj (a : as) g t c v d = calFromAdj as g t c v $
calToTarget g t a (Set.insert c v) (calFromCurrent (a : as) c v d)
calFromCurrent [] _ _ d = d
calFromCurrent (a : as) c v d
| notMember a v = calFromCurrent as c v $
Map.insert a (min (lookup' a d) (lookup' c d + 1)) d
| otherwise = calFromCurrent as c v d
lookup' k m = fromJust $ Map.lookup k m
-- test below,
{-
a-S---b-c
\ |\
\ | \
\| \
d-e-T-f
-}
g = fromList
[
("a", ["S"]),
("S", ["a", "b", "d"]),
("b", ["S", "c", "d", "T"]),
("c", ["b"]),
("d", ["S", "b", "e"]),
("e", ["d", "T"]),
("T", ["b", "e", "f"]),
("f", ["T"])
]
infinity = 99
d = fromList
[
("a", infinity),
("S", infinity),
("b", infinity),
("c", infinity),
("d", infinity),
("e", infinity),
("T", infinity),
("f", infinity)
]
v = empty
s = "S"
t = "T"
-- The shortest distance will equal 2 from "S" to "T" below,
main = do
print . lookup' t . calToTarget g t s v $ Map.insert s 0 d