达到基本情况后无法从 Prolog 中的递归取回我的结果

Can't get my results back from recursion in Prolog after reaching base case

我正在尝试了解 Prolog 递归的工作原理。由于某种原因,在达到基本情况后,它会展开所有结果。这是代码:

makeMove([0 | Tail], List).
makeMove([Head | Tail], List) :-
    Head1 is Head - 1,
    makeMove([Head1 | Tail], [[Head1 | Tail] | List]).

move(InputList, Output) :-
    makeMove(InputList, Output).

我在这里要做的是生成列表的列表,可以通过从输入列表的第一个元素中减去 1 直到它为 0 来形成列表。 这是堆栈跟踪:

[trace]  ?- 
|    move([3,4,5], X).
   Call: (8) move([3, 4, 5], _23538) ? creep
   Call: (9) makeMove([3, 4, 5], _23538) ? creep
   Call: (10) _23792 is 3+ -1 ? creep
   Exit: (10) 2 is 3+ -1 ? creep
   Call: (10) makeMove([2, 4, 5], [[2, 4, 5]|_23538]) ? creep
   Call: (11) _23816 is 2+ -1 ? creep
   Exit: (11) 1 is 2+ -1 ? creep
   Call: (11) makeMove([1, 4, 5], [[1, 4, 5], [2, 4, 5]|_23538]) ? creep
   Call: (12) _23840 is 1+ -1 ? creep
   Exit: (12) 0 is 1+ -1 ? creep
   Call: (12) makeMove([0, 4, 5], [[0, 4, 5], [1, 4, 5], [2, 4, 5]|_23538]) ? creep
   Exit: (12) makeMove([0, 4, 5], [[0, 4, 5], [1, 4, 5], [2, 4, 5]|_23538]) ? creep
   Exit: (11) makeMove([1, 4, 5], [[1, 4, 5], [2, 4, 5]|_23538]) ? creep
   Exit: (10) makeMove([2, 4, 5], [[2, 4, 5]|_23538]) ? creep
   Exit: (9) makeMove([3, 4, 5], _23538) ? creep
   Exit: (8) move([3, 4, 5], _23538) ? creep
true 

最内层调用中Output的值是上一次调用的值加上一些东西,但Prolog变量是不可变的。你所拥有的是一个中间状态。从上次结果中获取,需要第三个参数:

makeMove([0 | Tail], Result, Result).

makeMove([Head | Tail], List, Result) :-
    Head1 is Head - 1,
    makeMove([Head1 | Tail], [[Head1 | Tail] | List], Result).

move(InputList, Output) :-
    makeMove(InputList, [], Output).

这不是您唯一的问题,但这应该可以帮助您渡过难关。

如果成功证明给出的查询,Prolog 会向我们报告查询中存在的所有自由变量。例如,证明

?- move([3,4,5], X).

如果成功(并且将会成功),将向我们报告 X 现在持有的值。

这将是......仍然只是 X,因为你什么都不做。

你的证明会在 X 的基础上添加一些东西,但是当到达最终案例时,所有这些东西都不会绑定到从顶部查询可以到达的任何东西。 X 作为输入,没有任何输出记录。

为了得到这个"output",通常采用丹尼尔的回答中给出的解决方案——另一个,第三个参数被提供给查询,一直不变地传递,并且只绑定在最深的子句当构建完整的解决方案时达到。

此时 Prolog 将暂停,并向我们报告我们在查询中提供的所有自由变量。其中之一将是刚刚设置为引用刚刚构建的完整解决方案的那个。