Functional programming 树上的尾部递归

Functional programming 树上的尾部递归,functional-programming,sml,Functional Programming,Sml,我有一个数据结构 datatype 'a tree = Leaf | Branch of 'a tree * 'a * 'a tree 我想写一个函数,以某种顺序遍历这棵树。它做什么并不重要,所以它可以是一个树的形式:('a*'b->'b)->'b->'a tree->'b。我可以这样写这个函数: fun treefold f acc1 Leaf = acc1 | treefold f acc1 (Branch (left, a, right)) = let val acc2 =

我有一个数据结构

datatype 'a tree = Leaf | Branch of 'a tree * 'a * 'a tree
我想写一个函数,以某种顺序遍历这棵树。它做什么并不重要,所以它可以是一个
树的形式:('a*'b->'b)->'b->'a tree->'b
。我可以这样写这个函数:

fun treefold f acc1 Leaf = acc1
  | treefold f acc1 (Branch (left, a, right)) =
    let val acc2 = treefold f acc1 left
        val acc3 = f (a, acc2)
        val acc4 = treefold f acc3 right
    in acc4 end
但因为在最后一种情况下我不可避免地有两个分支,所以这不是尾部递归函数


如果允许扩展类型签名,那么是否可以创建一个类型签名,代价是什么?我还想知道它是否值得一试;也就是说,它在实践中是否有任何速度优势?

您可以使用连续传递样式实现尾部递归树形:

fun treefold1 f Leaf acc k = k acc
  | treefold1 f (Branch (left, a, right)) acc k =
    treefold1 f left acc (fn x => treefold1 f right (f(a, x)) k)

fun treefold f t b = treefold1 f t b (fn x => x)
例如:

fun sumtree t = treefold op+ t 0

val t1 = Branch (Branch(Leaf, 1, Leaf), 2, Branch (Leaf, 3, Leaf))

val n = sumtree t1

与@seanmcl编写类似,将函数转换为尾部递归的系统方法是使用连续传递样式

之后,您可能希望具体化您的延续,并使用更具体的数据类型,例如列表:

fun treefoldL f init tree =
    let fun loop Leaf acc [] = acc
          | loop Leaf acc ((x, right) :: stack) =
            loop right (f(x,acc)) stack
          | loop (Branch (left, x, right)) acc stack =
            loop left acc ((x, right) :: stack)
    in  loop tree init [] end

看这个:谢谢你,肯。我之所以这么问,主要是因为我不耐烦地埋伏在其他人问SML问题时,并认为我会问一个人们可能愿意回答的问题(H&R的新书中似乎增加了一个关于延续的新篇章。)