Maa*_*gon 4 erlang strict stack-trace lazy-evaluation
当出现问题时,Erlang会产生很好的堆栈跟踪,当程序员想弄清楚它出错的原因时,这很有用.在存在更高阶函数的情况下,产生堆栈跟踪的机制似乎不足.例如,比较下面的两个例子(我在代码的注释中添加了生成的堆栈跟踪).
我读过之前为延迟评估(例如在Haskell中)生成堆栈跟踪的困难.但是由于Erlang被严格评估,我原本期望得到更好的结果.
我的问题是:什么使高阶函数成为Erlang用于生成堆栈跟踪的机制的问题?还有其他已知技术会产生更好的结果吗?
1 -module(test).
2 -export([f/1,a/1]).
3
4 % Auxilary function to print stack trace (by throwing an exception).
5
6 s(X) when X < 0 -> 0.
7
8 % Example 1: Stack trace in presence of a higher order function.
9 %
10 % > test:f(1).
11 % ** exception error: no function clause matching test:s(1) (test.erl, line 6)
12 % in function test:g/2 (test.erl, line 15)
13
14 f(X) -> h(fun g/2,X).
15 g(X,Y) -> s(X) - Y.
16 h(I,X) -> I(X,3).
17
18 % Example 2: Stack trace for chain of 1st order function applications.
19 %
20 % > test:a(1).
21 % ** exception error: no function clause matching test:s(1) (test.erl, line 6)
22 % in function test:c/1 (test.erl, line 28)
23 % in call from test:b/1 (test.erl, line 27)
24 % in call from test:a/1 (test.erl, line 26)
25
26 a(X) -> b(X) + 1.
27 b(X) -> c(X) + 2.
28 c(X) -> s(X) + 3.
Run Code Online (Sandbox Code Playgroud)
这不是使用高阶函数本身的结果,而是尾部调用优化的结果.如果函数在返回之前做的最后一件事是调用另一个函数,那么Erlang VM会优化掉堆栈帧,因为它不再需要了.(这就是为什么你可以在没有溢出堆栈的情况下进行递归的原因.)
在你的榜样,两者f
并h
做尾调用,因此,他们的堆栈帧不在堆栈跟踪可见.在另一方面,a
,b
和c
不做尾调用,因为他们必须执行他们返回给调用之前调用的函数的结果的加法.
归档时间: |
|
查看次数: |
126 次 |
最近记录: |