使用函数保护理解 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. 如果列表头与第一个参数匹配,在本例中为 1,则列表头不会保存在任何地方,即它被跳过,函数是用列表的尾部再次调用:

     delete(Del, [Del|Xs]) ->
         delete(Del, Xs);
    
  2. 如果列表的头部与第一个参数不匹配,则通过将列表的头部添加到结果列表来保存列表的头部:

    [X|delete(Del, Xs)].
    
  3. 当列表为空时,函数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);