使用函数保护理解 Erlang 基本递归
Understanding Erlang Basic recursion with function guards
我一直在查看之前在 Whosebug 上询问的一些 Erlang 递归示例。
专门针对这个问题Erlang basic recursion with guards
但我不太明白代码是如何工作的。所以我创建了一个模块来查看结果returns,其中包含一个包含 3 个元素的简单列表。
-module(recursion).
-export([start/0]).
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(_, []) ->
io:format("return []~n~n~n"),
[];
delete(Del, [Del|Xs]) ->
io:format("~p =:= ~p~n",[Del,Del]),
io:format("delete(~p, ~p)~n~n~n~n",[Del,Xs]),
delete(Del, Xs);
delete(Del, [X|Xs]) ->
io:format("~p =/= ~p~n",[Del,X]),
io:format(" [~p|delete(~p, ~p)]~n~n~n~n",[X,Del,Xs]),
[X|delete(Del, Xs)].
这是日志的结果
1> recursion:start().
1 =:= 1
delete(1, [2,3])
1 =/= 2
[2|delete(1, [3])]
1 =/= 3
[3|delete(1, [])]
return [] The result of the 'Final' variable of the main function, shouldn't it be []?
bacause [3|delete(3, [])] in the last call matches with delete(_, []) -> []
or is it this way? [2,[3,[]]] -> [2,3]
[2,3]
2>
我的问题是:
程序每次调用delete(Del, [X|Xs]) ->,函数是不是把值返回给上一次调用?
它被存储在某个地方吗?
还是只是类似的东西? [2,[3,[]]] -> [2,3]
编辑:
我想我已经在这个 link 中找到了解决方案,关于最终结果是如何构建的
https://learnyousomeerlang.com/starting-out-for-real#lists
其中
13> List = [2,3,4].
[2,3,4]
14> NewList = [1|List].
[1,2,3,4]
所以 [2|[3|[]]] -> [2,3]
是这样吗?
是的。
函数是这样工作的:
如果列表头与第一个参数匹配,在本例中为 1
,则列表头不会保存在任何地方,即它被跳过,函数是用列表的尾部再次调用:
delete(Del, [Del|Xs]) ->
delete(Del, Xs);
如果列表的头部与第一个参数不匹配,则通过将列表的头部添加到结果列表来保存列表的头部:
[X|delete(Del, Xs)].
当列表为空时,函数returns []
,这在cons'ing元素时非常重要:
[3 | f(X) ]
如果 f(X) 在某些时候不是 return 列表,则该列表将不是 proper
列表。一个合适的列表,例如:
[1, 2, 3]
相当于:
[1 | [2 | [3 | [] ]]]
如您所见:
2> [1 | [2 | [3 | [] ]]].
[1,2,3]
当你写:
[X|delete(Del, Xs)]
这有点棘手,您需要一些经验才能知道它是如何工作的。通过手写正在发生的事情,您可以更好地理解事情:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ] %% Can't know the result here without determining the return value of delete(1, [3])
|
V
[3 | delete(1, []) ] %% Can't know the result here without determining the return value of delete(1, [])
|
V
[]
一次,您得到了 return 值 []
,因为结果中没有更多的函数调用,现在您可以向上移动替换:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ]
|
V
[3 | [] ]
再次代入:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | [3 | [] ] ]
相当于:
[2, 3]
这里是 delete()
的概念上更简单的版本:
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(Term, List) ->
delete(Term, List, _Acc=[]).
delete(_, [], Acc) ->
Acc;
delete(Term, [Term|Xs], Acc) ->
delete(Term, Xs, Acc);
delete(Term, [X|Xs], Acc) ->
delete(Term, Xs, [X|Acc]).
然而,结果是:
[3, 2]
所以,当你使用一个累加器变量时,你需要反转最终结果:
delete(_, [], Acc) ->
lists:reverse(Acc);
我一直在查看之前在 Whosebug 上询问的一些 Erlang 递归示例。
专门针对这个问题Erlang basic recursion with guards
但我不太明白代码是如何工作的。所以我创建了一个模块来查看结果returns,其中包含一个包含 3 个元素的简单列表。
-module(recursion).
-export([start/0]).
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(_, []) ->
io:format("return []~n~n~n"),
[];
delete(Del, [Del|Xs]) ->
io:format("~p =:= ~p~n",[Del,Del]),
io:format("delete(~p, ~p)~n~n~n~n",[Del,Xs]),
delete(Del, Xs);
delete(Del, [X|Xs]) ->
io:format("~p =/= ~p~n",[Del,X]),
io:format(" [~p|delete(~p, ~p)]~n~n~n~n",[X,Del,Xs]),
[X|delete(Del, Xs)].
这是日志的结果
1> recursion:start().
1 =:= 1
delete(1, [2,3])
1 =/= 2
[2|delete(1, [3])]
1 =/= 3
[3|delete(1, [])]
return [] The result of the 'Final' variable of the main function, shouldn't it be []?
bacause [3|delete(3, [])] in the last call matches with delete(_, []) -> []
or is it this way? [2,[3,[]]] -> [2,3]
[2,3]
2>
我的问题是: 程序每次调用delete(Del, [X|Xs]) ->,函数是不是把值返回给上一次调用? 它被存储在某个地方吗? 还是只是类似的东西? [2,[3,[]]] -> [2,3]
编辑: 我想我已经在这个 link 中找到了解决方案,关于最终结果是如何构建的 https://learnyousomeerlang.com/starting-out-for-real#lists 其中
13> List = [2,3,4].
[2,3,4]
14> NewList = [1|List].
[1,2,3,4]
所以 [2|[3|[]]] -> [2,3]
是这样吗?
是的。
函数是这样工作的:
如果列表头与第一个参数匹配,在本例中为
1
,则列表头不会保存在任何地方,即它被跳过,函数是用列表的尾部再次调用:delete(Del, [Del|Xs]) -> delete(Del, Xs);
如果列表的头部与第一个参数不匹配,则通过将列表的头部添加到结果列表来保存列表的头部:
[X|delete(Del, Xs)].
当列表为空时,函数returns
[]
,这在cons'ing元素时非常重要:[3 | f(X) ]
如果 f(X) 在某些时候不是 return 列表,则该列表将不是 proper
列表。一个合适的列表,例如:
[1, 2, 3]
相当于:
[1 | [2 | [3 | [] ]]]
如您所见:
2> [1 | [2 | [3 | [] ]]].
[1,2,3]
当你写:
[X|delete(Del, Xs)]
这有点棘手,您需要一些经验才能知道它是如何工作的。通过手写正在发生的事情,您可以更好地理解事情:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ] %% Can't know the result here without determining the return value of delete(1, [3])
|
V
[3 | delete(1, []) ] %% Can't know the result here without determining the return value of delete(1, [])
|
V
[]
一次,您得到了 return 值 []
,因为结果中没有更多的函数调用,现在您可以向上移动替换:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ]
|
V
[3 | [] ]
再次代入:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | [3 | [] ] ]
相当于:
[2, 3]
这里是 delete()
的概念上更简单的版本:
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(Term, List) ->
delete(Term, List, _Acc=[]).
delete(_, [], Acc) ->
Acc;
delete(Term, [Term|Xs], Acc) ->
delete(Term, Xs, Acc);
delete(Term, [X|Xs], Acc) ->
delete(Term, Xs, [X|Acc]).
然而,结果是:
[3, 2]
所以,当你使用一个累加器变量时,你需要反转最终结果:
delete(_, [], Acc) ->
lists:reverse(Acc);