Haskell 在函数中使用递归二叉树列表遍历数据类型

Haskell 在函数中使用递归二叉树列表遍历数据类型,haskell,Haskell,我创建了一个递归二叉树,其中可以有无限的子级: data Tree a = Leaf a | Node [Tree a] data Tree a = [...] 我的问题在于创建函数以遍历树的语法 假设我想做一些简单的事情,比如给一个参数1,然后找出树中是否出现了1。当节点是[treea]而不是节点[Leaf-root-Leaf]时,我对函数定义有问题。我不习惯在变量中调用列表的函数 下面是它如何处理更简单的递归数据类型: occs :: Eq a => a -

我创建了一个递归二叉树,其中可以有无限的子级:

data Tree a = Leaf a
            | Node [Tree a]
data Tree a = [...]
我的问题在于创建函数以遍历树的语法

假设我想做一些简单的事情,比如给一个参数1,然后找出树中是否出现了1。当
节点
[treea]
而不是
节点[Leaf-root-Leaf]
时,我对函数定义有问题。我不习惯在变量中调用列表的函数

下面是它如何处理更简单的递归数据类型:

occs :: Eq a => a -> Tree a -> Bool 
occs x (Leaf y) = x == y
occs x (Node left y right) = x == y || occs x left || occs x right
但是,
(节点左y右)
不再合适,因为
节点
现在是一个列出的树
[树a]
。如何将列出的树
[treea]
作为变量进行操作


如果出现,预期结果将是
True
False
,但问题主要在于识别函数中列出的
[树a]
的语法。我尝试了多种编写方法,但它总是返回错误。

您只需要递归检查任何分支(我称之为列表中的树)是否包含
x
。幸运的是,前奏曲包含了一个功能,使这一过程变得非常简单:

occs :: Eq a => a -> Tree a -> Bool 
occs x (Leaf y) = x == y
occs x (Node branches) = any (occs x) branches

any
如果您愿意,也很容易自己实现)

既然Robin Zigmond回答了您的问题,“如何将列出的树
[tree a]
作为一个变量来操作?”,我将尝试不同的回答

我创建了一个递归二叉树,其中可以有无限的子级:

data Tree a = Leaf a
            | Node [Tree a]
data Tree a = [...]
那么它不是二进制而是n元

此确切类型已存在于模块下的
容器
包中

Data.Tree
为其定义了一组类型类实例,其中一个是,并且您正在编写的函数已经位于
Data.Foldable
的名称下,并且具有以下类型:

elem :: (Eq a, Foldable t) => a -> t a -> Bool
因此,如果您选择的数据类型是n元树,
data.tree
elem
将是正确的选择


另一方面,如果您所追求的是一个具有两个子节点的实际二叉树,那么定义此二叉树并使其成为可折叠的实例将以相同的方式为您提供
elem

{-# LANGUAGE DeriveFoldable #-}

data BinaryTree a
  = Leaf
  | Node a (BinaryTree a) (BinaryTree a)
  deriving (Foldable)

-- now `elem` comes for free
Edit:根据amalloy的建议,派生了可折叠的
实例

但由于
elem
仅受
Eq a
约束,而不是
Ord a
,因此无法获得二进制搜索树的O(log n)查找,因此如果需要,您必须将其称为其他名称:

occs :: Ord a => a -> BinaryTree a -> Bool
occs _ Leaf = False
occs x (Node y left right) =
  case x `compare` y of
    LT -> occs x left
    EQ -> True
    GT -> occs x right

如果您不向我们展示您的尝试,我们无法帮助您了解您的尝试出了什么问题。因此,请包含您认为应该工作但不工作的代码,以及您收到的错误消息。在
leafy
中,您是
leafa
构造函数。
节点[Tree a]
构造函数的有效匹配项为:
节点
节点[]
节点[x]
(或
节点(x:[])
),
节点[x,y]
(或
节点(x:y:[])
,等等。
example4
的定义是什么?所以你可以随意命名它,它只代表列表。但最后一个问题是:如何创建一个要测试的示例<代码>示例::树a示例=节点[(叶1)(叶7)(叶8)]
这看起来不错,尽管类型是
树a Int
(任何数字类型都可以代替
Int
,但实际上并不重要)。另外,如果我想的话,我可以实现
任何
,这是什么意思。它可以被定义而不是调用库函数吗?是的,我只是想说它不是标准库为我们提供的一些“神奇”函数-像大多数库函数一样,它是为了方便而存在的,但是如果需要的话,可以很容易地在Haskell的几行代码中实现。既然它是为我们提供的,那么你就不需要亲自编写它,除非是作为练习。@Drake从你的错误中看出,你有一个
example5
,我假设它是一个树,你调用
occs example5
来运行测试。但是,
occs
接受两个参数,而不是一个。例如,
occs 7示例5
。手工编写可折叠实例很快就会让人厌烦。相反,使用DeriveFoldable派生它们。