【问题标题】:Processing successors in dfs with Haskell使用 Haskell 处理 dfs 中的后继者
【发布时间】:2022-01-06 07:21:36
【问题描述】:

考虑下面的 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。)

我的问题:你会如何在 Haskell 中写 get_successor_results

一些想法:

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\'}

    标签: haskell depth-first-search fold


    【解决方案1】:

    直接翻译它看起来很简单:

    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 代码相同的名称。

    【讨论】:

    • 有趣的是,某些函数似乎需要强制编写。我想知道他们有什么区别。也许其中一个特点是他们希望在其组件之间有很多共享状态(例如,堆栈帧之间的共享状态)。你遇到过这方面的写作吗?
    • @EricAuld 我认为有些作者似乎想要强制写作。这绝对不是我做 DFS 的方式。请参阅优秀论文Inductive Graphs and Functional Graph Algorithms 了解替代方案。
    • 你看到有人在 Erwig 的图书馆之外尝试这种解构方法吗?原则上似乎可以使用普通的邻接表示来做到这一点,边走边删除边和节点。持久数据结构可以帮助它不消耗太多空间。
    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多