F#使用连续尾递归将树叶转换为列表

3
我有一棵有树枝和叶子的类型树。我想要得到叶子值的列表。目前,我只能计算树枝的数量。
我的树:
type 'a tr =
  | Leaf   of 'a
  | Branch of 'a tr * 'a tr

我的代码:
let getList (tr:float tr)=
    let rec toList tree acc =
        match tree with
        | Leaf _ -> acc 0
        | Branch (tl,tr) -> toList tl (fun vl -> toList tr (fun vr -> acc(vl+vr+1)))
    toList tr id     

输出:

输入:

 let test=Branch (Leaf 1.2, Branch(Leaf 1.2, Branch(Branch(Leaf 4.5, Leaf 6.6), Leaf 5.4)))
 getList test

因此,我想得到一个列表:
[1.2; 1.2; 4.5; 6.6; 5.4]

我尝试过一些类似的变化,但没有成功。
  | Branch (tl,tr) -> toList tl (fun vl -> toList tr (fun vr -> (vl::vr)::acc))
    toList tr [] 

任何帮助都将不胜感激。
2个回答

3

这是由于您的连续函数(acc)签名为(int -> 'a) 如果您想要获取一个扁平化的列表,则连续函数的签名应该为('a list -> 'b)

let getList tree =
    let rec toList tree cont =
        match tree with
        | Leaf a -> cont [a]
        | Branch (left, right) -> 
            toList left (fun l -> 
                toList right (fun r -> 
                    cont (l @ r)))
    toList tree id

编辑:这应该更有效率

let getList tree = 
    let rec toList tree cont acc =
        match tree with 
        | Leaf a               -> cont (a :: acc)
        | Branch (left, right) -> toList left (toList right cont) acc
    toList tree id [] |> List.rev

3
请注意,您的树类型无法表示仅具有一个子节点的节点。类型应为:
type Tree<'T> =
    | Leaf of 'T
    | OnlyOne of Tree<'T>
    | Both of Tree<'T> * Tree<'T>

如果要使用尾递归和 continuation,请使用continuation函数,而不是累加器(accumulator)

let leaves tree =
    let rec collect tree cont =
        match tree with
        | Leaf x -> cont [x]
        | OnlyOne tree -> collect tree cont
        | Both (leftTree, rightTree) ->
            collect leftTree (fun leftAcc ->
                collect rightTree (fun rightAcc ->
                    leftAcc @ rightAcc |> cont))
    collect tree id

P/S:您的命名不太好:tr有太多的含义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接