Haskell 用二叉树中的数据记录所有路径

Haskell 用二叉树中的数据记录所有路径,haskell,Haskell,我正在尝试编写一个函数,其中记录所有指向数据N的路径 当我感到困惑时,谁能给我一些提示,我什么时候记录路径?好像我从一开始就开始,我可能最终会找到通往哪里的路。(记录路径为L | R) 谁能给我讲点道理 谢谢 我在给定路径的树上工作过,但我搞不懂这一点 data Tree = N | F Tree Tree deriving Show data Dir = L | R deriving Show type Path = [Dir] 所以树可以是fn(F(fnn)(fn(fnn))

我正在尝试编写一个函数,其中记录所有指向数据N的路径

当我感到困惑时,谁能给我一些提示,我什么时候记录路径?好像我从一开始就开始,我可能最终会找到通往哪里的路。(记录路径为L | R)

谁能给我讲点道理

谢谢

我在给定路径的树上工作过,但我搞不懂这一点

data Tree = N | F Tree Tree deriving Show
data Dir = L | R deriving Show
type Path = [Dir]       
所以树可以是
fn(F(fnn)(fn(fnn))
路径应该是
[L,L,L,R]

我做了一些函数,可以在有N个节点的地方或在给定的路径上插入


但我无法理解记录路径的逻辑。

这不是一个完整的答案,但我的想法是这样的:您可以对树进行深度优先搜索(简单的递归调用),并确保在向上的过程中返回正确的内容。你知道当你递归到一个子子树时,你会得到一个返回的路径列表,对吗?然后,您只需要考虑如何在给定子问题的情况下获得答案:在本例中,将路径扩展到您迄今为止所走过的路径。我会写这样的东西

search N = [[]] -- one empty path
search (F x y) = map (L:) (search x) ++
    map (R:) (search y)
也就是说,将
Left
前置到来自左侧子问题的解,并将
Right
前置到来自右侧子问题的解

main = print . findAllLeaves $ F N (F (F N N) (F N (F N N)))

data Tree = N | F Tree Tree deriving Show
data Dir = L | R deriving Show
type Path = [Dir]    

descend :: Tree -> Dir -> Tree
descend (F l _) L = l
descend (F _ r) R = r
descend _ _ = undefined

findAllLeaves :: Tree -> [Path]
findAllLeaves N = [[]]
findAllLeaves tree = do dir <- [L, R]
                        map (dir:) $ findAllLeaves (descend tree dir)
我使用列表单子“同时”选择L和R,并使两个分支下降。一定要爱不确定性


说明:

我希望
下降
足够清晰。你给它一棵树和一个方向,它沿着这个方向下降

findalleaves
是一个有趣的例子。它是如何工作的

稍后我们将讨论基本情况,
findalleaves N=[[]]

递归的大小写在列表monad中,使用
do
表示法。第一行很简单:选择
L
R
并将其分配给
dir
列表单子实际上会同时选择两者,并将每个单子的结果连接在一起。这是理解它们的关键。这正是您所要求的:以
L
开头的所有路径是什么,以
R
开头的所有路径是什么?把这些放在一起,就有了从当前节点到其子叶节点的所有路径

第二行应该与上一段的描述相当清楚。沿着给定的方向下降树(
下降树目录
),找到该点的所有树叶(
FindAlleLaves
),然后将选择的方向预先添加到每个子路径(
映射(目录:)

那么为什么基本情况是
[[]]
?好吧,考虑一下基本情况之上的情况。例如,
findalleaves(fnn)
。当我们选择
dir=L
时,我们计算第二行:

map (L:) $ findAllLeaves (descend (F N N) L)
从左向下只给我们提供
N

map (L:) $ findAllLeaves N
然后我们讨论了基本情况:

map (L:) $ [[]]
现在你能明白为什么我们有那个奇怪的基本情况吗?里面有空列表的列表?因为我们将把
(L:)
映射到它上面,换句话说,将
L
前置到外部列表中的每个列表。这导致:

[[L]]
dir=R
时,我们得到了类似的结果

[[R]]
然后列表单子将它们连接在一起

[[L]] ++ [[R]]
而我们最终得到的是

[[L], [R]]

如果其中任何一个仍然不清楚,请在评论中告诉我,我会尽力澄清。

这是一个二叉树,对吗?分类了吗?你现在有什么代码?是的,它没有排序,我有这个代码到目前为止,更新你可以缩进四个空格的代码片段,使他们格式化为这样。您也可以突出显示它们,然后按标签为
{}
findalleaves::Tree->[Path]
-这是您正在寻找的函数所需的类型签名吗?看到基本案例帮助我意识到我的解决方案有什么问题。谢谢这真的很好,我真的不明白发生了什么,它有点先进的地方我at@Lunar“单子列表”一开始也让我感到困惑。在我的解释之后,它开始有意义了。你可能想先读一下这些书中前面的内容。@luqui我当时有点匆忙。我现在添加了一个关于它如何工作的解释。加粗的段落有望足以解释使用列表单子的动机。
[[L], [R]]