【问题标题】:Tail recursive reading of file OCaml文件OCaml的尾递归读取
【发布时间】:2020-04-07 22:52:03
【问题描述】:

我写了一个函数来打印文件的所有内容

let rec print_file channel =
    try
    begin
        print_endline (input_line channel);
        print_file channel
    end
    with End_of_file -> ()

由于 print_file 是最后一个操作,我认为它将被优化为常规循环。但是当我在非常大的文件上运行我的程序时,我遇到了堆栈溢出。 因此,我尝试将 input_line 函数包装到 input_line_opt 中,该函数不会引发异常并且几乎不会更改 print_file 的代码。


let input_line_opt channel = 
    try Some (input_line channel)
    with End_of_file -> None

let rec print_file channel =
    let line = input_line_opt channel in
    match line with
        Some line -> (print_endline line; print_file channel)
        | None -> ()

现在它就像常规的尾递归函数一样工作,并且不会溢出我的堆栈。 这两个函数有什么区别?

【问题讨论】:

    标签: exception ocaml stack-overflow tail-recursion


    【解决方案1】:

    在第一个示例中,try ... with 是在递归调用 print_file 之后发生的操作。所以函数不是尾递归的。

    你可以想象try在栈中设置了一些数据,with从栈中移除了数据。由于你在递归调用之后删除了数据,因此堆栈越来越深。

    这在 OCaml 的早期版本中一直存在。编写用于处理文件的尾递归代码很棘手。在最近的修订中,您可以使用 matchexception 子句来获取递归调用的尾部位置:

    let rec print_file channel =
        match input_line channel with
        | line -> print_endline line; print_file channel
        | exception End_of_file -> () 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多