在尝试返回用Prolog编写的列表中的倒数第二个元素的问题时感到困惑。这种语言使用起来很有趣,但是我无法绕过它。这就是我所拥有的:
secondLast([X], X).
secondLast(X, [Y], X) :- secondLast(Y, K).
secondLast(X, [Y|Z], K) :- secondLast(Y, Z, K).
secondLast([X|Z], Ans) :- secondLast(X, Z, Ans).
所以致电secondLast([a, b, c, d], X).
X
应该等于c
。
有什么想法吗?
谢谢!
答案 0 :(得分:5)
可以只是:
secondLast(L, X) :-
append(_, [X, _], L).
答案 1 :(得分:5)
你应该应用模式匹配:
secondLast([X,_], X).
secondLast([_|T], X) :- secondLast(T, X).
答案 2 :(得分:3)
Sergey和CapelliC为这个问题提供了两个不错的解决方案。让我们来看看原作的错误:
1) secondLast([X], X).
2) secondLast(X, [Y], X) :- secondLast(Y, K).
3) secondLast(X, [Y|Z], K) :- secondLast(Y, Z, K).
4) secondLast([X|Z], Ans) :- secondLast(X, Z, Ans).
在Prolog中,由于它是关于定义具有谓词的实体之间的关系,而不是定义函数,因此有助于描述谓词的含义,"某些事情是真的如果其他一些事情是真的"。 Prolog中的 if 表示为:-
。
我们会看第4条,因为这似乎是你的主要条款。这个说,* Ans
是[X|Z]
的倒数第二个元素,如果Ans
是以Z
作为头部的X
的倒数第二个元素?目前还不清楚这个secondLast
的3参数版本意味着什么。但是,如果列表是3个或更多元素,则X
似乎变得无关紧要(如第2和第3条所示)。
第1条说明, X
是列表[X]
中倒数第二个元素。但是,元素X
是列表[X]
中的 last 和 only 元素。所以这个条款在逻辑上是不正确的。
第2条有点令人困惑。它在子句K
中引入了一个变量,该变量仅使用一次,未在子句中的任何其他位置定义或使用。它也忽略了X
,因为如上所述,它已经变得无关紧要,因为它不再是倒数第二个元素的候选者。 Prolog已经给出了关于单例元素K
和X
的警告,这类似于C中的警告,即变量是定义但从未使用过的#34;或者"被分配一个从未使用的值"。条款#3有同样的问题。
在所有这些中,我想我可以看到你想要做的事情,也就是说, Ans
是[X|Z]
的最后一个元素,如果有的话在X
之后的另一个元素,这将是真的,但如果列表[X|Z]
是2元素列表,则仅限于正确。换句话说,你的主要条款几乎假定答案最终是X
。如果不是,它会尝试在第2和第3条中引入新的候选人Y
,但是这个候选人无法回复"原来的主要条款。
我现在回到CapelliC的解决方案,并描述一个人如何做到这一点:
1) secondLast([X,_], X).
2) secondLast([_|T], X) :- secondLast(T, X).
第一个子句说, X
是2元素列表中的倒数第二个元素,[X,_]
是真的。而且我们并不关心最后一个元素是什么,所以我们只是称之为_
。我们可以称之为Y
([X,Y]
),但是由于我们不需要或使用Y
,Prolog会警告单个变量。
第二个条款说, X
是列表[_|T]
的倒数第二个元素,如果X
是尾部的倒数第二个元素T
。这也是任何3个或更多元素列表的。自基础案例第一部分以来,这很好,它负责2元素列表。第二条将以递归的方式减少到第一条,最后以正确的答案成功。在第二个条款中,如果X
取自T
,那么我们就不关心列表的头部是什么,因为它变得无关紧要,所以我们使用_
作为X
在这种情况下的头部(这对应于原始条款#4中的secondLast(L, X) :-
append(_, [X, _], L).
。
谢尔盖的回答:
X
这就是说, L
是列表L
中倒数第二个元素,如果X
是一个以[X,_]
作为第一个元素的双元素列表({{ 1}})附加到其他列表的末尾(_
)。请再次注意我们将_
用于具有值的变量但我们不会#39在这种情况下,关心这些值是什么。因此,例如: 2
是[1,2,3]
的倒数第二个元素,如果[1,2,3]
[2,_]
附加到其他列表,它是:如果您将[2,3]
追加到[1]
,则会获得[1,2,3]
。