使用 Haskell 在 dfs 中处理后继者
Processing successors in dfs with Haskell
考虑以下 Python 函数,它在给定节点的后继者的情况下访问它们并收集结果。 (在实践中,此逻辑将构成递归 visit
函数的一部分。)
from typing import Any, Callable, Tuple, List, Set
Node_key = Any
Discovered = Set[Node_key]
Result = Any
def get_successor_results(visit: Callable[[Discovered, Node_key],
Tuple[Discovered, Result]],
successors: List[Node_key],
disc: Discovered) -> List[Result]:
results = []
for succ in successors:
if succ not in disc:
disc, result = visit(disc, succ)
results.append(result)
return results
(对于上下文,这将是 df-traverse 函数的一部分,给定一个图和一个函数 combiner :: Node_key -> [Result] -> Result
相当于构建深度优先森林并调用 fold-tree combiner
每棵树。)
My Question: How would you write get_successor_results
in Haskell?
一些想法:
get-successor-results visit successors disc =
reverse . first . conditional-fold
(\(d, _) node -> not (elem node d))
(cons-next-result visit)
(empty-set, [])
successors
where
cons-next-result visit _@(disc, results) node =
let (disc-new, result) = visit disc node
in (disc-new, result:results)
conditional-fold p folder e xs = case xs of
{[] -> e;
x:xs' -> if p e x then conditional-fold p folder (folder e x) xs'
else conditional-fold p folder e xs'}
直接翻译看起来很简单:
get_successor_results ::
(node_key -> discovered -> Bool) ->
(node_key -> State discovered result) ->
[node_key] ->
State discovered [result]
get_successor_results not_in visit successors = do
results <- for successors $ \succ -> do
should_visit <- gets (succ `not_in`)
if should_visit
then Just <$> visit succ
else return Nothing
return (catMaybes results)
希望与您的 Python 代码的相似之处很清楚。这里唯一真正的转折点是使用 Nothing
作为您不想访问的后继者的占位符,并在第二步将它们剥离。当然,我建议你使用驼峰命名;这是 Haskell 中的一个强有力的约定,因此它将更好地融入现有的库调用,但我希望相似之处尽可能明显,所以我尽可能使用与您的 Python 代码相同的名称。
考虑以下 Python 函数,它在给定节点的后继者的情况下访问它们并收集结果。 (在实践中,此逻辑将构成递归 visit
函数的一部分。)
from typing import Any, Callable, Tuple, List, Set
Node_key = Any
Discovered = Set[Node_key]
Result = Any
def get_successor_results(visit: Callable[[Discovered, Node_key],
Tuple[Discovered, Result]],
successors: List[Node_key],
disc: Discovered) -> List[Result]:
results = []
for succ in successors:
if succ not in disc:
disc, result = visit(disc, succ)
results.append(result)
return results
(对于上下文,这将是 df-traverse 函数的一部分,给定一个图和一个函数 combiner :: Node_key -> [Result] -> Result
相当于构建深度优先森林并调用 fold-tree combiner
每棵树。)
My Question: How would you write
get_successor_results
in Haskell?
一些想法:
get-successor-results visit successors disc =
reverse . first . conditional-fold
(\(d, _) node -> not (elem node d))
(cons-next-result visit)
(empty-set, [])
successors
where
cons-next-result visit _@(disc, results) node =
let (disc-new, result) = visit disc node
in (disc-new, result:results)
conditional-fold p folder e xs = case xs of
{[] -> e;
x:xs' -> if p e x then conditional-fold p folder (folder e x) xs'
else conditional-fold p folder e xs'}
直接翻译看起来很简单:
get_successor_results ::
(node_key -> discovered -> Bool) ->
(node_key -> State discovered result) ->
[node_key] ->
State discovered [result]
get_successor_results not_in visit successors = do
results <- for successors $ \succ -> do
should_visit <- gets (succ `not_in`)
if should_visit
then Just <$> visit succ
else return Nothing
return (catMaybes results)
希望与您的 Python 代码的相似之处很清楚。这里唯一真正的转折点是使用 Nothing
作为您不想访问的后继者的占位符,并在第二步将它们剥离。当然,我建议你使用驼峰命名;这是 Haskell 中的一个强有力的约定,因此它将更好地融入现有的库调用,但我希望相似之处尽可能明显,所以我尽可能使用与您的 Python 代码相同的名称。