OCaml中函数组合的尾部递归版本
非尾部递归组合函数可以这样编写:OCaml中函数组合的尾部递归版本,ocaml,Ocaml,非尾部递归组合函数可以这样编写: 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
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)))
让rec组合l k=
如果k List.length l,则[]
否则,如果k=1,则List.map(fun x->[x])l
其他的
让hd,tl=List.hd l,List.tl l进入
组合tl k |>List.rev_append(List.map(funx->hd::x)(组合tl(k-1)))
请注意,我使用了List.rev_append
,至少给定了append
一个尾部递归版本
这意味着,如果您想从列表中获取k个元素,则生成所有组合
我只是想知道是否有可能创建一个总尾部递归版本的组合
?您可以使用:
让组合Lk=
让rec aux l k cont=
如果k列表长度为l,则继续[]
否则,如果k=1,则继续(List.map(fun x->[x])l)
其他的
让hd,tl=List.hd l,List.tl l进入
辅助TLK
(
乐趣res1->辅助tl(k-1)
(
fun res2->cont(List.rev_append(List.map(fun x->hd::x)res2)res1)
)
)
在辅助LK(乐趣x->x)
这样,您就可以避免在递归调用
aux
之后调用某个函数,而代价是创建一个匿名函数,该函数用于解释“原始递归调用”之后将要进行的“未来计算”。通常我们会采用延续传递方式,如Phimueme的回答。例如
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
还有其他更自然的方法吗?@JacksonTale这正是我问自己的,我不得不说我不确定。但是从我(承认是非常有限的)经验来看,如果您的原始函数依赖于多个递归调用,那么编写相应的尾部递归版本通常是很麻烦的。您能给出更多的解释吗?什么是
提示
,算法是什么?这是生成组合吗?不,这是树的前缀遍历:type'a tree=Tip | Node of'a tree*'a*'a tree
——这不适用于组合,只是我决定在这里加上的一般性注释。
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