Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 构建树中所有分支的列表_Haskell_Tree - Fatal编程技术网

Haskell 构建树中所有分支的列表

Haskell 构建树中所有分支的列表,haskell,tree,Haskell,Tree,我需要让函数返回树中所有可能的分支 使用此表格: data Tree a = EmptyT | NodeT a ( Tree a ) ( Tree a ) deriving (Show) everyBranch :: Tree a -> [[a]] 我不知道该怎么做。。。除息的 我还是哈斯克尔的新手 假设我有: 1 / \ 2 3 /\ / \ 4 5 7 8 我想得到:[[

我需要让函数返回树中所有可能的分支 使用此表格:

data Tree a = EmptyT | NodeT a ( Tree a ) ( Tree a ) deriving (Show)

everyBranch :: Tree a -> [[a]]
我不知道该怎么做。。。除息的 我还是哈斯克尔的新手

假设我有:

            1
           / \
          2   3
         /\  / \
        4  5 7  8

我想得到:
[[1,2,4],[1,2,5],[1,3,8],[1,3,7]
我们将使用递归方法。让我们从一个粗略的骨架开始:

everyBranch :: Tree a -> [[a]]
everyBranch EmptyT = _something
everyBranch (NodeT v (Tree l) (Tree r)) = _somethingElse
现在我们来填补这些漏洞。(这种语法称为“类型化孔”:如果您通过GHC运行上述程序,它将给您一条错误消息,其中包含应在孔中的值的类型。)现在,我不确定第一种情况:根据您的需要,它可能是
[]
(无分支)或
[[]]
(一个分支没有元素),所以我们稍后再讨论这个问题。对于第二种情况,我们需要一种方法来构造给定
v
值和
l
eft和
r
ights子树的分支列表。我们怎么做?我们将递归地查找
l
eft树中的每个分支,以及
r
ight树中的每个分支,然后我们将
v
前置到这两个树:

everyBranch :: Tree a -> [[a]]
everyBranch EmptyT = _something
everyBranch (NodeT v l r) = map (v:) $ everyBranch l ++ everyBranch r
现在,让我们回到
EmptyT
。考虑一个非常简单的树:<代码> NoDET 1 EMPTYT EMPTYT。在这种情况下,
everyBranch
应该返回
[[1]]
。让我们在这棵树上手动调用everyBranch:

(我使用
└→
表示“递归计算子表达式”,而
=>
表示“表达式计算为”)

所以在这里,我们希望
map(1:)$\u something++\u something
等于
[[1]]
。什么是什么东西?事实证明,如果某个东西是
[]
,那么
map(1:)$[]+[]
就是
[]
,这不是我们想要的。另一方面,如果某个东西是
[[]]
,那么
map(1:)$[[]]+[[]]]
就是
[[1],[1]]
,这也不是我们想要的。看起来我们需要一个稍微不同的方法。我们将要做的是,我们将为这类树添加另一个案例:

everyBranch :: Tree a -> [[a]]
everyBranch EmptyT = _something
everyBranch (NodeT v EmptyT EmptyT) = [[v]]
everyBranch (NodeT v l r) = map (v:) $ everyBranch l ++ everyBranch r

现在,如果我们稍微测试一下(尽管对
\u something
使用一些随机值来阻止它给我们带来错误),我们发现它适用于所有二叉树。如前所述,我们仍然需要计算出
\u某物的值。此值仅在两种情况下起作用:空树(在这种情况下,它将与
EmptyT
)和只有一个子树的树(在这种情况下,
l
r
将与
EmptyT
匹配)。我将把它作为一个练习留给您来确定放在那里的值,它将如何影响结果,以及它为什么会以这种方式影响结果。

我们可以派生并使用
Foldable
,折叠成一个特殊的monoid来完成这项工作:

data Tree a = EmptyT
            | NodeT a ( Tree a ) ( Tree a )
            deriving (Show, Functor, Foldable)

data T a = T a                    -- tip
         | N [[a]]                -- node
         | TN (a,[[a]])           -- tip  <> node
         | NN ([[a]],[[a]])       -- node <> node
         deriving Show

instance Monoid (T a) where
    mempty = N []           -- (tip <> node <> node)  is what we actually want
    mappend (T a)  (N as) = TN (a,as)           -- tip  <> node
    mappend (N as) (N bs) = NN (as,bs)          -- node <> node

    mappend (T a) (NN ([],[])) = N ([[a]])      -- tip  <> (node <> node)
    mappend (T a) (NN (as,bs)) = N (map (a:) as ++ map (a:) bs) 

    mappend (TN (a,[])) (N []) = N ([[a]])      -- (tip <> node) <> node
    mappend (TN (a,as)) (N bs) = N (map (a:) as ++ map (a:) bs)

allPaths :: Tree a -> [[a]]
allPaths (foldMap T -> N ps) = ps
(提示节点)
是我们真正想要的,但是
是二进制的,我们不知道(如果我们知道的话,也不应该依赖它)根据
foldMap
的派生定义将部分组合成整体的实际顺序

foldMap T EmptyT          ==  N []
foldMap T (NodeT a lt rt) ==  T a <> foldMap T lt <> foldMap T rt
                              -- but in what order? 
foldMap T EmptyT==N[]
折叠贴图T(节点a lt rt)=T a折叠贴图T lt折叠贴图T rt
--但顺序是什么?
因此,我们通过延迟实际组合直到三个部分都可用,来“伪造”

或者我们可以完全放弃派生路线,使用上述定律作为自定义
foldMap
的定义,使用三元组合,最终得到。。。与另一个答案中的递归代码相当——总体上要短得多,没有需要隐藏在模块墙后面的一次性辅助类型的实用性缺陷,并且不言而喻是非局部的,这与我们最终得到的不同

所以也许不是很好。无论如何,我会把它贴出来,作为对位

> allPaths $ NodeT 1 (NodeT 2 (NodeT 3 EmptyT EmptyT) EmptyT) 
                     (NodeT 5 EmptyT EmptyT)
[[1,2,3],[1,5]]

> allPaths $ NodeT 1 (NodeT 2 (NodeT 3 EmptyT EmptyT) (NodeT 4 EmptyT EmptyT)) 
                     (NodeT 5 EmptyT EmptyT)
[[1,2,3],[1,2,4],[1,5]]
foldMap T EmptyT          ==  N []
foldMap T (NodeT a lt rt) ==  T a <> foldMap T lt <> foldMap T rt
                              -- but in what order?