Recursion Erlang-递归后列表/元组层次结构的问题

Recursion Erlang-递归后列表/元组层次结构的问题,recursion,erlang,Recursion,Erlang,这个递归的结果树不是什么I什么,这可能证明我不完全理解递归中列表/元组的行为。如果有人能解释我在这个例子中做错了什么,并解释正确的思考方式,我将非常感激 move([],{Main, One, Two}) -> {Main, One, Two}; move([X|Xr], {Main, One, Two}) -> [{Main, One, Two}, move(Xr, single(X, {Main, One, Two}))]. 所需结果(一个包含3个元组的列表):

这个递归的结果树不是什么I什么,这可能证明我不完全理解递归中列表/元组的行为。如果有人能解释我在这个例子中做错了什么,并解释正确的思考方式,我将非常感激

move([],{Main, One, Two}) ->
    {Main, One, Two};
move([X|Xr], {Main, One, Two}) ->
    [{Main, One, Two}, move(Xr, single(X, {Main, One, Two}))].
所需结果(一个包含3个元组的列表):

实际结果(包含元组和列表的列表,包含元组和列表…):


在编写这样的列表时,您希望使用
|
而不是

move([X|Xr], {Main, One, Two}) ->
    [{Main, One, Two} | move(Xr, single(X, {Main, One, Two}))].
递归调用返回一个列表,该列表将嵌套得越来越深,除非您使用
|
将它们展平一点。这与模式匹配中的概念相同,只是使用了一个反向操作。

您有两个问题:

  • |
    而不是@nmichaels提到的
  • 函数
    move/2
    返回一个列表,因此终止子句也必须返回一个列表。在您的示例中没有看到这一点,因为第一个问题隐藏了它
  • 因此产生的代码是:

    move([X|Xr], {Main, One, Two}) ->
        [{Main, One, Two} | move(Xr, single(X, {Main, One, Two}))];
    move([], {Main, One, Two}) ->
        [{Main, One, Two}].
    
    我改变了条款的顺序,因为我个人更喜欢这样写。在这种情况下没有根本区别。我假设
    single/2
    返回一个元组

    实际上,您可以通过从
    move/2
    中删除元组的所有知识来优化此代码,因为它从未实际使用内部结构。因此:

    move([X|Xr], Tuple) ->
        [Tuple | move(Xr, single(X, Tuple))];
    move([], Tuple) ->
        [Tuple].
    

    我试过了,但结果会更好,但并不完美:
    [{[a,b],[]},{[a],[b],[b],[a]}{[b],[a]}{[b],[a]}]
    答案中仍然有“|”。它将X应用于主列表,1和2,并返回{MainX,OneX,TwoX},一个包含3个列表的元组。解决了它!我添加了一个累加器(我想),一个空列表,我在其中存储状态,而不是在从递归向上添加状态<代码>移动([],元组,Y)->追加(Y,[元组]);move([X | Xr],Tuple,Y)->move(Xr,single(X,Tuple),append(Y,[Tuple])。说这是尾部递归是正确的吗?
    move([X|Xr], {Main, One, Two}) ->
        [{Main, One, Two} | move(Xr, single(X, {Main, One, Two}))];
    move([], {Main, One, Two}) ->
        [{Main, One, Two}].
    
    move([X|Xr], Tuple) ->
        [Tuple | move(Xr, single(X, Tuple))];
    move([], Tuple) ->
        [Tuple].