Ocaml 如何使用尾部递归重写代码

Ocaml 如何使用尾部递归重写代码,ocaml,Ocaml,我只是想寻求一些建议,如何使用尾部递归重写代码 open Core.Std;; let rec dig x = match x with | 0 -> [] | _ -> x :: dig (x - 1) ;; let () = let numbers = dig 10 in List.iter ~f:(Printf.printf "%d, ") numbers; Printf.printf "\n"; ;; 任何建议都会有帮

我只是想寻求一些建议,如何使用尾部递归重写代码

open Core.Std;;

let rec dig x =
    match x with
    | 0 -> []
    | _ -> x :: dig (x - 1)
;;


let () = 
    let numbers = dig 10 in
    List.iter ~f:(Printf.printf "%d, ") numbers;
    Printf.printf "\n";
;;
任何建议都会有帮助

let dig x =
    let rec f x s =
        match x with
        | 0 -> s
        | _ -> f (x-1) (x::s)
    f x []
这是你想要的吗?它使用尾部递归

编辑: 对于递减序列,只需将(x::s)替换为(List.append s[x])或(s@[x]),但这不是一个好主意,List.rev更好:

let dig x =
    let rec f x s =
        match x with
        | 0 -> s
        | _ -> f (x-1) (s @ [x])
    f x []
这是你想要的吗?它使用尾部递归

编辑: 对于递减序列,只需将(x::s)替换为(List.append s[x])或(s@[x]),但这不是一个好主意,List.rev更好:

let dig x =
    let rec f x s =
        match x with
        | 0 -> s
        | _ -> f (x-1) (s @ [x])
    f x []
不确定这是否会使您的船漂浮:您可能需要调整边界情况,具体取决于您希望0还是包含起始编号


不确定这是否会使您的船漂浮:您可能需要调整边界情况,这取决于您是否想要0或包含起始编号。

嗯,似乎可以有多种解决方案

open Core.Std;;


let rec digtail ?(l=[]) x =
    match x with
    | 0 -> l
    | _ -> digtail ~l: (l @ [x]) (x - 1)
;;


let () = 
    let numbers = digtail 10 in
    List.iter ~f:(Printf.printf "%d, ") numbers;
    Printf.printf "\n";
;;

多亏了大家,你帮了大忙。

嗯,似乎可以有多种解决方案

open Core.Std;;


let rec digtail ?(l=[]) x =
    match x with
    | 0 -> l
    | _ -> digtail ~l: (l @ [x]) (x - 1)
;;


let () = 
    let numbers = digtail 10 in
    List.iter ~f:(Printf.printf "%d, ") numbers;
    Printf.printf "\n";
;;

感谢大家,您帮了很多忙。

如果您不想在向后构建列表后使用
List.rev
(我认为这很好),也不想用
0
而不是
n
开始递归,您可以使用某种延续:

let dig2 x =
  let rec aux x kont =
    match x with
     | 0 -> kont
     | _ -> aux (x-1) (fun l -> kont (x::l))
in
aux x (fun l -> l) [];;

基本上,每个步骤都会返回一个函数,根据剩余步骤生成的列表,该函数将附加
x
。我们用identity函数开始递归,因为我们还没有任何东西要构建。然后,当我们退出递归时,我们只需将空列表应用于获得的函数。

如果您不想在向后构建列表(我认为这很好)后使用
list.rev
,也不想用
0
而不是
n
开始递归,您可以使用某种延续:

let dig2 x =
  let rec aux x kont =
    match x with
     | 0 -> kont
     | _ -> aux (x-1) (fun l -> kont (x::l))
in
aux x (fun l -> l) [];;

基本上,每个步骤都会返回一个函数,根据剩余步骤生成的列表,该函数将附加
x
。我们用identity函数开始递归,因为我们还没有任何东西要构建。然后,当我们退出递归时,我们只需将空列表应用于获得的函数。

这不是我想要的。您的函数生成递增序列,但我正在尝试创建递减序列。您应该使用
List.rev
反转结果以保留顺序这不是我想要的。您的函数使用递增序列,但我正在尝试创建递减序列。您应该使用
List来反转结果。rev
保留顺序
l@[x]
使您的函数是二次的,而不是线性的:对于每个调用,您将遍历迄今为止为附加单个元素而构建的整个
l
。此外,
@
本身不是尾部递归的,因此实际上您正在将问题从
digtail
转移到
@
。您确实应该更喜欢Syeerzi的解决方案(使用ivg建议的最终
List.rev
l@[x]
使您的函数是二次函数而不是线性函数:对于每个调用,您都在遍历迄今为止为附加单个元素而构建的整个
l
。此外,
@
本身不是尾部递归的,因此实际上您正在将问题从
digtail
转移到
@
。你真的应该更喜欢Syeerzi的解决方案(使用ivg建议的最终
List.rev
)你知道,这不是我不喜欢List.rev或内部递归函数的解决方案,我只是想找到更多的方法来解决这个简单的任务。我只是开始学习OCaml,想看看其他人如何在简单任务中使用它。(关于我的英语学习,我也能说同样的话。)我没问题。我只是想强调一个事实,前两个答案比我的更为惯用,这确实只是为了完整起见。“你可以使用某种延续”,也称为
差异列表
。你知道,这不是我不喜欢List.rev或内部递归函数的解,我只是想找到更多的方法来解决这个简单的任务。我只是开始学习OCaml,想看看其他人如何在简单任务中使用它。(关于我的英语学习,我也能说同样的话。)我没问题。我只是想强调一个事实,前两个答案比我的更为惯用,这确实只是为了完整起见。“你可以使用某种延续”,也称为
差异列表