windows - 递归函数调用挂起,Erlang

标签 windows memory erlang erlang-shell

我目前正在自学 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 ,然后稍微思考一下您在示例代码中看到的列表操作示例。

注意事项

  1. 在运算符周围放置空格是一件好事;它会防止你用彼此相邻的箭头和二进制语法运算符做混淆的事情,同时避免一些其他的歧义(无论如何它更容易阅读)。

  2. 正如 Steve 所指出的,您注意到的内存爆炸是因为虽然您的函数是递归的,但它不是尾递归 -- 也就是说,1 + list_length(Xs) 留下待完成的工作,这必须在堆栈上留下一个引用。要让任何东西加 1,必须完成 list_length/1 的执行,返回一个值,在这种情况下,记住挂起值的次数与列表中的成员数一样多。阅读 Steve 的回答,了解如何使用 accumulator 值编写尾递归函数的示例。

关于windows - 递归函数调用挂起,Erlang,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29866490/

相关文章:

java - Jenkins 调用批处理文件卡在Windows 7中

windows - 如何禁用或更改 IntelliJ IDEA 启动画面?

c++ - 使用 Windows USB 虚拟 Com 端口识别断开连接事件

mysql - 连接 mySQL 和 Nodejs

erlang - 如何从erlang读/写到命名管道?

php - 在一台专用服务器 ubuntu 上运行多个 nginx

Java使用HashMap进行内存管理

python - 将 python 字典的最坏情况时间复杂度优化为 O(1)

ssl - Erlang YAWS https 税

functional-programming - Erlang中列表的笛卡尔幂