我目前正在自学 Erlang。一切都很顺利,直到我发现这个功能有问题。
-module(chapter).
-compile(export_all).
list_length([]) -> 0;
list_length([_|Xs]) -> 1+list_length([Xs]).
这是从教科书上摘下来的。当我使用 OTP 17 运行这段代码时,它只是挂起,这意味着它只是如下所示。
1> c(chapter).
{ok,chapter}
2> chapter:list_length([]).
0
3> chapter:list_length([1,2]).
在任务管理器中查看时,Erlang OTP 使用了 200 Mb 到 330 Mb 的内存。是什么原因造成的。
最佳答案
它不会终止,因为您在每种情况下都创建了一个新的非空列表:[Anything]
始终是一个非空列表,即使该列表仅包含一个空列表成员([[]]
是一个成员的非空列表)。
一个合适的列表像这样终止:[ Something | [] ]
.
考虑到这一点......
list_length([]) -> 0;
list_length([_|Xs]) -> 1 + list_length(Xs).
在大多数函数式语言中,“适当的列表”是 cons 风格的列表。查看the Wikipedia entry on "cons"和 the Erlang documentation about lists ,然后稍微思考一下您在示例代码中看到的列表操作示例。
注意事项
在运算符周围放置空格是一件好事;它会防止你用彼此相邻的箭头和二进制语法运算符做混淆的事情,同时避免一些其他的歧义(无论如何它更容易阅读)。
正如 Steve 所指出的,您注意到的内存爆炸是因为虽然您的函数是递归的,但它不是尾递归 -- 也就是说,
1 + list_length(Xs)
留下待完成的工作,这必须在堆栈上留下一个引用。要让任何东西加 1,必须完成list_length/1
的执行,返回一个值,在这种情况下,记住挂起值的次数与列表中的成员数一样多。阅读 Steve 的回答,了解如何使用 accumulator 值编写尾递归函数的示例。
关于windows - 递归函数调用挂起,Erlang,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29866490/