You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell二叉树前序遍历函数类型签名疑问咨询

理解通用二叉树前序遍历的函数声明

嘿,我来帮你拆解一下你看到的那个函数声明,顺便梳理下你自己的代码问题,很快就能搞明白啦!

首先先说说你自己的代码:你定义的Tree类型是这样的:

data Tree = Node Int Tree Tree | Leaf Int deriving (Eq,Show)

这个树的节点和叶子都只能存Int类型,所以你最初设想的preorder :: Tree -> [a]其实不太准确——因为你的树里只有Int,没法返回任意类型a的列表,正确的声明应该是preorder :: Tree -> [Int]才对。

接下来解释你看到的那个通用版函数声明:preorder :: (a -> c) -> (b -> c) -> Tree -> [c]。这个函数其实是针对更灵活的二叉树类型设计的,不是你现在用的这个只存Int的特定树。

拆解这个函数的参数与用途

这个函数确实接收三个输入:

  • 第一个参数(a -> c):这是一个转换函数,用来把树节点中存储的a类型值,转换成我们最终想要的c类型。
  • 第二个参数(b -> c):另一个转换函数,用来把树叶子中存储的b类型值,也转换成c类型。
  • 第三个参数Tree:这里的Tree其实是一个通用二叉树类型,比如它的定义可能是这样的:
    data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b deriving (Eq,Show)
    
    也就是说,这个树的节点可以存任意a类型,叶子可以存任意b类型(a和b可以是不同类型)。

函数的返回值[c],就是把整个树里的所有节点、叶子,都通过前面两个转换函数统一成c类型后,按前序遍历顺序收集起来的列表。

举个例子更直观

假设我们有一个通用树,节点存字符串,叶子存整数:

myTree :: Tree String Int
myTree = Node "foo" (Leaf 1) (Node "bar" (Leaf 2) (Leaf 3))

如果我们想把整个树的元素都转成字符串,然后前序遍历输出,就可以这样调用那个通用函数:

preorder id show myTree

这里:

  • id :: String -> String:直接保留节点的字符串值
  • show :: Int -> String:把叶子的整数转换成字符串
    最终会得到结果:["foo", "1", "bar", "2", "3"]

回到你自己的场景

你的Tree里节点和叶子都是Int,如果用这个通用函数的话,相当于a和b都是Int,我们可以传入两个id函数(直接返回原Int值),这样调用后就和你想要的功能完全一致:

preorder id id :: Tree -> [Int]

不过对你的特定Tree类型来说,完全没必要这么麻烦,直接写一个只处理Int的前序遍历函数就好,比如:

preorder :: Tree -> [Int]
preorder (Leaf x) = [x]
preorder (Node x left right) = x : preorder left ++ preorder right

内容的提问来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:41:31