Exception 文件OCaml的尾部递归读取
我写了一个函数,可以像那样打印文件的所有内容Exception 文件OCaml的尾部递归读取,exception,ocaml,stack-overflow,tail-recursion,Exception,Ocaml,Stack Overflow,Tail Recursion,我写了一个函数,可以像那样打印文件的所有内容 let rec print_file channel = try begin print_endline (input_line channel); print_file channel end with End_of_file -> () 因为print_文件是最后一个操作,所以我认为它将被优化为常规循环。但当我在一个很大的文件上运行我的程序时,我的堆栈溢出了。 所以我尝试将i
let rec print_file channel =
try
begin
print_endline (input_line channel);
print_file channel
end
with End_of_file -> ()
因为print_文件是最后一个操作,所以我认为它将被优化为常规循环。但当我在一个很大的文件上运行我的程序时,我的堆栈溢出了。
所以我尝试将input_line函数包装为input_line_opt,这样不会引发异常,也不会对print_文件产生太多更改代码
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 -> ()
现在,它的工作原理类似于常规的尾部递归函数,不会使堆栈溢出。
这两个函数之间有什么区别?在第一个示例中,
试试。。。with
是在递归调用print_file
之后发生的操作。因此,函数不是尾部递归的
您可以想象try
在堆栈上设置一些数据,而with
从堆栈中删除数据。由于在递归调用之后删除了数据,堆栈变得越来越深
在OCaml的早期版本中,这是一个一致的问题。编写用于处理文件的尾部递归代码很棘手。在最近的版本中,您可以使用match
的exception
子句来获取递归调用的尾部位置:
let rec print_file channel =
match input_line channel with
| line -> print_endline line; print_file channel
| exception End_of_file -> ()