首页 > 解决方案 > 关于 SWI Prolog 中列表的规则匹配

问题描述

最近我开始学习 Prolog,作为一个练习,我尝试实现一个谓词penultimate/2,给出一个不会回溯的列表的倒数第二个元素。

这个问题在使用削减时是微不足道的,但我尝试以与 SWI-Prolog 实现last/2不使用削减的谓词类似的方式实现谓词:

penultimate([X1, X2 | Rest], Elem) :-
  penultimate_([X1, X2 | Rest], X1, X2, Elem).

penultimate_([], X1, _, X1).
penultimate_([_], _, X2, X2).
penultimate_([X1, X2 | Rest], _, _, Penultimate) :-
  penultimate_(Rest, X1, X2, Penultimate).

当列表的长度为偶数时,此代码按预期工作,但是当输入奇数长度的列表时,我得到以下结果:

?- penultimate([1,2,3], X).
X = 2 ;
false.

我能想到的发生这种情况的唯一原因是 SWI-Prolog 匹配系统将我程序中的规则视为匹配单元素列表的可能性,即使规则头中的列表至少需要 2 个元素. 这个对吗?

标签: prolog

解决方案


尝试:

penultimate([X1, X2 | Rest], Penultimate) :-
    penultimate(Rest, X1, X2, Penultimate).

penultimate([], Penultimate, _, Penultimate).
penultimate([X3| Rest], _, X2, Penultimate) :-
    penultimate([X2, X3| Rest], Penultimate).

示例调用:

| ?- penultimate([1,2,3,4,5], P).

P = 4

yes
| ?- penultimate([1,2,3,4], P).  

P = 3

yes
| ?- penultimate([1,2,3], P).  

P = 2

yes
| ?- penultimate([1,2], P).  

P = 1

yes
| ?- penultimate([1], P).  

no

大多数 Prolog 系统上的索引可以区分空列表(原子)或非空列表(复合术语),但通常不会在列表中执行深度索引。


推荐阅读