如何在Haskell中更加惯用地改进最短距离的计算?

时间:2015-04-01 01:38:04

标签: haskell

我已经尝试根据下面的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

0 个答案:

没有答案