Tree 使用reduce和map遍历n元树的SML
我是SML的新手 假设我有以下数据类型:Tree 使用reduce和map遍历n元树的SML,tree,sml,Tree,Sml,我是SML的新手 假设我有以下数据类型: datatype 'a tree = leaf of 'a | node of 'a tree list 函数val leaves=fn:'a tree->'是一个列表: fun leaves (leaf x) = [x] | leaves (node []) = [] | leaves (node [x]) = leaves x | leaves (node (x::xs)) = (leaves x) @ (leaves (node xs
datatype 'a tree = leaf of 'a | node of 'a tree list
函数val leaves=fn:'a tree->'是一个列表
:
fun leaves (leaf x) = [x]
| leaves (node []) = []
| leaves (node [x]) = leaves x
| leaves (node (x::xs)) = (leaves x) @ (leaves (node xs))
如果我有
val t = node [node [leaf 1,
node [leaf 2, leaf 3],
leaf 4]];
然后,leaves t
将为我返回[1,2,3,4]
我想问的是,这是否可以通过使用reduce
和map
重写
鉴于:
fun reduce g [x] = x
| reduce g (x::xs) = (g x (reduce g xs))
非常感谢。您似乎有一种反复出现的习惯,就是从太多的子句开始 从两个必要的方面开始:
fun leaves (leaf x) = [x]
| leaves (node xs) = ???
现在,xs
是一个列表。map
将列表转换为不同的列表。reduce
将列表缩减为单个值
这表明你想要某种形式的东西
| leaves (node xs) = reduce f (map g xs)
确定
f
和g
作为练习留在左侧。在ML中,有一种约定,在SML中没有语法强制,即数据构造函数以大写开头,值(包括函数)以小写开头。在模式匹配中,这使它们更容易区分,因为在语法上,节点可以是数据构造函数或变量,如果不检查整个代码,就无法分辨
StackOverflow倾向于同意我们的观点,因为它的语法highlighter不是非常上下文感知的,除非我们遵循这个约定,否则无法为数据构造函数绘制特殊的颜色
因此:
molbdnilo已经展示了如何简化leaves
中的模式
fun leaves (Leaf x) = [x]
| leaves (Node ts) = ???
(注意,我更改了构造函数的大小写,并将xs
重命名为ts
,因为它是一个树列表。)
为了使用递归来完成这个函数,我想说这里有两种方法。正如您将看到的,在两个方向上都有权衡,我将提到:
- 坚持使用两种模式,并在一个单独的、相互递归的函数中处理
xs
上的递归:
fun leaves (Leaf x) = [x]
| leaves (Node ts) = nodes ts
and nodes [] = []
| nodes (t::ts) = leaves n @ nodes ts
拥有两个可能互相调用的函数只是有点让人费解。您必须不断提醒自己,t
是一棵树,因此应该对其调用leaves
,但ts
是一个树列表,因此应该对其调用节点。但是除了在后续的、相互递归的函数上使用和
而不是fun
之外,语法也没那么糟糕
- 转到三种模式,通过匹配两个深度级别来处理树及其内部列表的递归:
fun leaves (Leaf x) = [x]
| leaves (Node []) = []
| leaves (Node (t::ts)) = leaves t @ leaves (Node ts)
只有一个函数似乎更简单,但缺点是模式匹配变得有点棘手:您不仅要匹配输入是一个节点
,还要特别匹配它是一个节点
,没有子节点(节点[]
),或者至少有一个子节点(节点(t::ts)
)。这里的复杂性在于,虽然模式匹配成功地解构了单个t
,可以递归地传递给leaves
(leaves t
),处理其余的ts
(一个“树列表”
),但您没有处理此类列表的函数。但您几乎可以这样做:如果您将节点
放回ts
(Node ts
),您将得到一个包含该子节点列表的'a树
。你有一个处理一棵树的函数
随着时间的推移,你可以自己决定哪种想法更难处理
也许在不同的场合你都喜欢
我想问的是,这是否可以通过使用reduce
和map
重写
是的。在研究了List.concat
之后,我知道f
和g
是什么样子!谢谢你的评论!我以前没有注意到命名约定。是的,我同意你的观点,我们应该坚持下去:)
fun leaves (Leaf x) = [x]
| leaves (Node []) = []
| leaves (Node (t::ts)) = leaves t @ leaves (Node ts)