非尾递归组合函数可以这样写:
let rec combinations l k =
if k <= 0 || k > List.length l then []
else if k = 1 then List.map (fun x -> [x]) l
else
let hd, tl = List.hd l, List.tl l in
combinations tl k |> List.rev_append (List.map (fun x -> hd::x) (combinations tl (k-1)))
请注意,我使用List.rev_append
至少给出append
尾部递归版
如果您想从列表中获取k个元素,则表示生成所有组合。
我只是想知道是否可以创建combinations
的尾递归版本?
答案 0 :(得分:0)
您可以使用continuation passing style:
let combos l k =
let rec aux l k cont =
if k <= 0 || k > List.length l then cont []
else if k = 1 then cont (List.map (fun x -> [x]) l)
else
let hd, tl = List.hd l, List.tl l in
aux tl k
(
fun res1 -> aux tl (k-1)
(
fun res2 -> cont (List.rev_append (List.map (fun x -> hd::x) res2) res1)
)
)
in aux l k (fun x -> x)
这样,你可以避免在aux
的递归调用之后调用某些东西,其代价是创建一个匿名函数,该函数解释了“原始递归调用”之后的“未来计算”。
答案 1 :(得分:0)
通常我们会按照phimuemue的答案进行连续传递式。 E.g。
let rec prefix_cps tree k =
match tree with
| Tip -> k []
| Node (left,n,right) ->
prefix_cps left (fun nleft ->
prefix_cps right (fun nright ->
k (n :: nleft @ nright)))
let prefix_cps t = prefix_cps t (fun l -> l)
但是,有时我们可以动态重新排列输入:
let rec prefix_tr t =
let rec loop queue = function
| Tip -> queue
| Node (l, n, Tip) -> loop (n::queue) l
| Node (l, k, Node (rl, n, rr)) ->
loop queue (Node (Node (l, k, rl), n, rr)) in
loop [] t