Prolog:关于列表和递归的代码说明

时间:2020-07-02 18:05:44

标签: prolog

以下代码有效,但如果需要帮助,以了解其工作方式。

%Multiplication of List Elements, Lists have same length

listmulti([],[],[]).
listmulti([H1|B1],[H2|B2],[Result|Spare]) :-
   listmulti(B1,B2,Spare),
   Result is H1 * H2.

所有内容都是可以理解的,但Spare变量则不可理解。没有它,代码将无法工作。

我在此处添加了Prolog跟踪,以查看会发生什么情况。

trace,(listmulti([2,1],[3,5],Result)).
 Call:listmulti([2, 1], [3, 5], _5956)
 Call:listmulti([1], [5], _6268)
 Call:listmulti([], [], _6274)
 Exit:listmulti([], [], [])
 Call:_6272 is 1*5
 Exit:5 is 1*5
 Exit:listmulti([1], [5], [5])
 Call:_6266 is 2*3
 Exit:6 is 2*3
 Exit:listmulti([2, 1], [3, 5], [6, 5])
Result = [6, 5]

_5956等数字是什么?来自Prolog的帮助变量? 备用变量会一直为空吗?为什么我需要备用变量?为什么我不能只写[Result]像这样

listmulti([H1|B1],[H2|B2],[Result])

感谢您的预先答复和最良好的问候。

1 个答案:

答案 0 :(得分:0)

Prolog通过将变量绑定绑定到项来传达计算结果。变量可以以 unbound 开始,即不绑定任何值,并且可以在计算过程中通过统一而绑定。

在某种程度上您已经知道这一点。毕竟,当您编写类似

的查询时
?- listmulti([2,1],[3,5],Result).

您没有为Result指定值-它是未绑定的。但是,当您运行查询时,Prolog会将Result绑定到一个词并告诉您它是什么:

Result = [6, 5].

我们可以通过调用Result在绑定之前和之后打印listmulti的值来可视化它:

?- write('before the query, Result is: '), write(Result), nl,
|    listmulti([2,1], [3,5], Result),
|    write('after the query, Result is: '), write(Result), nl.
before the query, Result is: _G1699
after the query, Result is: [6,5]
Result = [6, 5].

开头,Result只是一些未绑定的变量,在这种情况下显示为_G1699。 (不同的变量具有不同的数字,因此您可以区分它们。)运行查询后,该变量现在绑定到列表[6, 5]

这也是示踪剂告诉您的内容,尽管要花一些时间来读取其输出:

 Call:listmulti([1], [5], _6268)
 ...
 Exit:listmulti([1], [5], [5])

这是在执行listmulti([1], [5], Spare)之前和之后的一对状态。 Spare的当前实例在调用之前是未绑定的,之后则绑定到[5],因为listmulti计算了列表[1]和{{1}的元素乘积}。

现在考虑以下谓词版本:

[5]

当使用前两个参数中的两个数字列表进行调用时,从操作上讲,这会将这些列表分解为它们的头和尾,并计算出元素的尾元素乘积。其结果是listmulti([],[],[]). listmulti([H1|B1], [H2|B2], AllResults) :- listmulti(B1,B2, ResultsForTheTailsOfTheLists), Result is H1 * H2, AllResults = [Result | ResultsForTheTailsOfTheLists]. 的列表。磁头的乘积计算为ResultsForTheTailsOfTheLists。然后,完整列表的结果就是包含Result和所有Result的列表。这更清楚吗?

最后一个问题是,在Prolog中,您可以先创建列表和其他数据结构,然后再知道要在其中添加什么。您可以构建如下列表:

ResultsForTheTailsOfTheLists

但是您也可以先构建列表,然后再绑定其头部和尾部:

?- Head = a, Tail = [b, c], List = [Head | Tail].
Head = a,
Tail = [b, c],
List = [a, b, c].

这就是您最初的定义所发生的事情:在头上,一旦您知道要查看两个数字列表,便知道结果的格式为?- List = [Head | Tail], Head = a, Tail = [b, c]. List = [a, b, c], Head = a, Tail = [b, c]. 。在子句中具有该术语的标题可以立即构建它。仅在稍后,您才通过递归调用计算[HeadResult | TailResults]HeadResult。总体而言,这为您提供了完整的列表。