3

我正在尝试在序言中编写一个谓词来查找列表中的第 K 个元素。例子:

?- element_at(X,[a,b,c,d,e],3).
X = c

我的代码如下

k_ele(X,[X|_],1).
k_ele(X,[_|T],Y) :- Y > 1,Y is Y - 1, k_ele(X,T,Y).

但没用,我在网上找到了解决方案

element_at(X,[X|_],1).
element_at(X,[_|L],K) :- K > 1, K1 is K - 1, element_at(X,L,K1).

这与我的逻辑相同,只是他们使用了一个额外的变量 K1。

我的代码有什么问题,为什么我需要另一个变量?

4

3 回答 3

4

您的代码不起作用的原因是统一不是分配。当你说

Y is Y - 1

您正在尝试将 的值Y与 的值统一Y-1,这在数学上是不可能的。4 is 3这与说or大致相同1001 is 1000。整个条件失败,导致无法在列表中找到元素。

您在网上找到的固定解决方案引入了一个单独的变量K1,与K - 1. 这是非常可行的:K1获取K-1评估的值,条件成功,子句继续到递归调用部分。

于 2013-10-31T19:08:20.287 回答
2

因为 prolog 中的变量是一次写入的生物。已经[分配|统一|绑定]一个非变量值,它不再是变量。以后就是那个值了。与更多...常规...编程语言不同,一旦绑定,重新分配序言变量的唯一方法是回溯分配并撤消它。

但是应该注意,一个变量可以与另一个变量统一:给定一个谓词,例如

foo(X,Y) :- X = Y .

和类似的东西

shazam(X,Y) :- bar(X,Y) , X = 3.

将导致 X 和 Y 均为 3。统一后,X 和 Y 都是相同的变量,尽管名称不同。

于 2013-10-31T19:25:20.123 回答
1

我想您正在使用此链接中的练习:

http://www.ic.unicamp.br/~meidanis/courses/problemas-prolog/

请注意,在我看来,原始解决方案也不是最好的。

例如,一个查询:

element_at(X,[a,b,c],Y).

会崩溃,即使有 3 个解决方案:

  • X = a,Y = 1;
  • X = b,Y = 2;
  • X = c,Y = 3;

我相信以另一种方式写作:

element_at(H, [H | _], 1).
element_at(H, [_ | T], N) :- element_at(H, T, NMinus1), N is NMinus1 + 1.

会给出更好的结果。由于无法应用最后一次调用优化,因此效率较低,但逻辑变得更加通用。

于 2015-12-07T06:38:51.530 回答