理解顺序Erlang的问题

时间:2014-01-15 00:46:21

标签: erlang

我一直在研究一个代码示例,我无法理解正在发生的事情,我试图理解更简单的例子并得到它们但是在这一点我被卡住了:

seq([X, X | Xs]) -> [X | seq(Xs)];
seq([X, Y | Xs]) -> [X, Y | seq(Xs)];
seq(_) -> [].

当我用[1,1,1,2,2,2,3]在shell中运行它时,得到[1,1,2,2]。我一直试图通过将它写在纸上来理解这些步骤,但我陷入了困境。

我很感激所有答案向我解释这里发生的步骤! :) /蓖麻

2 个答案:

答案 0 :(得分:11)

好的,我们从[1,1,1,2,2,2,3]列表开始。

在第一次调用seq时,erlang会将前两个元素11seq - seq([X, X | Xs])的第一个“子句”匹配。 这将初始化将成为最终返回值[1, seq(Xs)]的列表。现在,此时Xs将绑定到值[1,2,2,2,3]。如果你想知道为什么在Xs列表的开头没有两个1,那是因为我们在[X, X | Xs]上匹配/绑定了其中两个。

返回值 = [1 | ?](?是要评估的剩余递归)
Xs = [1,2,2,2,3]

在第二次调用seq时,erlang会将输入列表1的前两个元素与2匹配到第二个子句seq([X, Y | Xs])。然后我们从此运行中“返回”列表[X,Y]或[1,2],并使用Xs = [2,2,3]调用下一次迭代。

返回值 = [1 | [1, 2 | ?]]< - 了解递归如何嵌套列表?
Xs = [2,2,3]

在第三次调用时,前两个元素再次相同,因此erlang再次运行第一个子句。 seq([X, X | Xs]) -> [X | seq(Xs)]。我们会在评估过程中返回一个2值,并调用seq([3])

返回值 = [1 | [1, 2 | [2 | ?]]]
Xs = [3]

最后,最后的案例。我们的[3]列表与[X, X | Xs][X, Y, Xs]不匹配,因此erlang将运行我们的全部:seq(_) -> []. _将匹配任何内容,而不绑定值对于任何局部变量,所以我们在这里做的就是返回一个空列表[]

我们的最终回报值是:[1 | [1, 2 | [2 | []]]]。如果你将它评估为你的erl repl,你会发现它与列表[1,1,2,2]相同,后者是前者的语法糖。

答案 1 :(得分:4)

跟踪可以帮到你一点点:

1> dbg:tracer().
{ok,<0.35.0>}
2> dbg:p(self(), [c]).
{ok,[{matched,nonode@nohost,1}]}
3> dbg:tpl({test, seq, 1}, [{'_',[],[{return_trace}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}
4> test:seq([1, 1, 1, 2, 2, 2, 3]).
(<0.33.0>) call test:seq([1,1,1,2,2,2,3])
(<0.33.0>) call test:seq([1,2,2,2,3])
(<0.33.0>) call test:seq([2,2,3])
(<0.33.0>) call test:seq([3])
(<0.33.0>) returned from test:seq/1 -> []
(<0.33.0>) returned from test:seq/1 -> [2]
(<0.33.0>) returned from test:seq/1 -> [1,2,2]
(<0.33.0>) returned from test:seq/1 -> [1,1,2,2]
[1,1,2,2]