我一直在研究一个代码示例,我无法理解正在发生的事情,我试图理解更简单的例子并得到它们但是在这一点我被卡住了:
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]。我一直试图通过将它写在纸上来理解这些步骤,但我陷入了困境。
我很感激所有答案向我解释这里发生的步骤! :) /蓖麻
答案 0 :(得分:11)
好的,我们从[1,1,1,2,2,2,3]
列表开始。
在第一次调用seq
时,erlang会将前两个元素1
和1
与seq
- 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]