Я бился головой от утечки из пространства Haskell (естественно, типа переполнения стека) в течение нескольких дней подряд.Это разочаровывает, потому что я пытаюсь подражать алгоритму BFS прямо из CLR, который не является естественно рекурсивным.NB: я включил BangPatterns и поставил удар перед каждым возможным местом, куда можно пойти, пытаясь разветвить и связать эту проблему, без эффекта.Раньше я боролся с космическими утечками, и я не собираюсь сдаваться и взывать о помощи, но в этот момент я застрял.Я люблю кодировать на Haskell, и я довольно хорошо понимаю дзен функционального программирования, но отладка пробелов в пространстве - это такое же удовольствие, как катание по полу, заполненному кнопками.
Тем не менее, моя проблема, похоже,космическая утечка типичного типа «аккумулятора».Стек явно создается вокруг вызовов bfs 'в приведенном ниже коде.Любые космические протекторы высоко ценятся.
import qualified Data.Map as M
import qualified Data.IntSet as IS
import qualified Data.Sequence as S
import qualified Data.List as DL
data BfsColor = White | Gray | Black deriving Show
data Node =
Node {
neighbors :: !IS.IntSet,
color :: !BfsColor,
depth :: !Int
}
type NodeID = Int
type NodeQueue = S.Seq NodeID
type Graph = M.Map NodeID Node
bfs :: Graph -> NodeID -> Graph
bfs graph start_node =
bfs' (S.singleton start_node) graph
bfs' :: NodeQueue -> Graph -> Graph
bfs' !queue !graph
| S.null queue = graph
| otherwise =
let (u,q1) = pop_left queue
Node children _ n = graph M.! u
(g2,q2) = IS.fold (enqueue_child_at_depth $ n+1) (graph,q1) children
g3 = set_color u Black g2
in bfs' q2 g3
enqueue_child_at_depth :: Int -> NodeID -> (Graph, NodeQueue)
-> (Graph, NodeQueue)
enqueue_child_at_depth depth child (graph,!queue) =
case get_color child graph of
White -> (set_color child Gray $ set_depth child depth graph,
queue S.|> child)
otherwise -> (graph,queue)
pop_left :: NodeQueue -> (NodeID, NodeQueue)
pop_left queue =
let (a,b) = S.splitAt 1 queue
in (a `S.index` 0, b)
set_color :: NodeID -> BfsColor -> Graph -> Graph
set_color node_id c graph =
M.adjust (\node -> node{color=c}) node_id graph
get_color :: NodeID -> Graph -> BfsColor
get_color node_id graph = color $ graph M.! node_id
set_depth :: NodeID -> Int -> Graph -> Graph
set_depth node_id d graph =
M.adjust (\node -> node{depth=d}) node_id graph