OCaml中的函数组合的尾递归版本

时间:2014-02-04 21:57:20

标签: 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 x -> hd::x) (combinations tl (k-1)))

请注意,我使用List.rev_append至少给出append尾部递归版

如果您想从列表中获取k个元素,则表示生成所有组合。

我只是想知道是否可以创建combinations的尾递归版本?

2 个答案:

答案 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