- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在解决 one of the OCaml tutorials 中发布的问题。其中之一是编写一个函数来计算列表的长度。它应该是尾递归的。
简单的非尾递归解决方案是:
let rec length_naive xs = (** Not tail recursive *)
match xs with
| [] -> 0
| _ :: xs -> 1 + length_naive xs;;
(length_naive [@tailcall]) [1, 2, 3, 4];;
let one_hundred_million = 100000000;;
let non_tail_result = length_naive(List.init one_hundred_million (Fun.id));;
print_endline("Non-tail-recursive result: " ^ string_of_int(non_tail_result));;
编译并运行它完全符合预期。打印警告(由于 @tailcall
),并且由于堆栈溢出而执行失败:
$ ocamlc lib/so.ml
File "lib/so.ml", line 14, characters 0-39:
14 | (length_naive [@tailcall]) [1, 2, 3, 4];;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Warning 51 [wrong-tailcall-expectation]: expected tailcall
$ ./a.out
Fatal error: exception Stack_overflow
现在是我尝试编写尾递归版本的时候了:
let length xs =
let rec f xs len =
match xs with
| [] -> len
| _ :: xs -> f xs (len + 1)
in
f xs 0;;
(length [@tailcall]) [1, 2, 3, 4];;
let one_hundred_million = 100000000;;
let tail_result = length(List.init one_hundred_million (Fun.id));;
print_endline("Tail recursive result: " ^ string_of_int(tail_result));;
编译并运行:
$ ocamlc lib/so.ml
File "lib/so.ml", line 15, characters 0-33:
15 | (length [@tailcall]) [1, 2, 3, 4];;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Warning 51 [wrong-tailcall-expectation]: expected tailcall
$ ./a.out
Tail recursive result: 100000000
所以它有效,堆栈溢出异常没有被抛出。但是,编译器会警告该函数不是尾递归的。我的问题是:
我使用的是 OCaml 编译器 v 4.14.0。
最佳答案
尾递归函数和尾调用可优化(函数)调用是两个不同的概念。 tail-call
是函数调用的属性,而 tail-recursive
是函数的属性。
在你的例子中
length []
是对尾递归函数的非尾调用优化调用。
length
定义内的函数调用是尾部调用可优化的:
let rec f xs len =
match xs with
| [] -> len
| _ :: xs -> (f[@tailcall]) xs (len + 1)
更明确地说,
当可以重用当前堆栈帧从而避免分配新的堆栈帧时,函数调用是尾部调用可优化的。特别是,如果可以快捷返回地址,则在递归函数定义内调用递归函数可能会重用父调用堆栈。
当函数体内对函数 f
的所有调用都是尾调用可优化时,该函数就是尾递归的。
关于ocaml - 为什么编译器认为这个函数是非尾递归的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73552447/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 4 年前。
我已更改 my.cnf。并检查sql_mode使用下面的命令 select @@global.sql_mode; 它说, 我也尝试过 set global sql_mode=''; SET sql_m
首先,我有一个结构,它有一个值和一个默认值 struct S { int a = 1; }; 当 gcc 和 clang 都是 non-const/non-constexpr 时,可以默认构造
我是一名优秀的程序员,十分优秀!