我想解决一个简单的问题,但即使我尝试了很多不同的方法,我也找不到解决方法。我正在使用SICStus Prolog(如果这很重要),我想得到一个列表的所有子列表/子集(我不知道哪个术语是正确的),其中包含连续的元素。例如,如果我有列表[1,2,3,4],将 sl/2
谓词调用为sl([1, 2, 3, 4], R).
,则预期结果为:
< / p>
? - sl([1, 2, 3, 4], R).
R = [] ? ;
R = [1] ? ;
R = [1, 2] ? ;
R = [1, 2, 3] ? ;
R = [1, 2, 3, 4] ? ;
R = [2] ? ;
R = [2, 3] ? ;
R = [2, 3, 4] ? ;
R = [3] ? ;
R = [3, 4] ? ;
R = [4] ? ;
no
到目前为止我能达到的最好结果是:
sl([], []).
sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
sl([_|Xs], Ys) :-
sl(Xs, Ys).
但这也为我提供了以下不需要的结果:
R = [1,2,4] ? ;
R = [1,3,4] ? ;
R = [1,3] ? ;
R = [1,4] ? ;
R = [2,4] ? ;
我应该如何修改谓词以便获得所需的结果?
答案 0 :(得分:4)
在Prolog中编写谓词时,您需要考虑谓词的含义,或者它定义的关系。你的谓词提供非解决方案的原因是你在谓词子句中混合含义。他们并非真正意味着同样的事情。
你有谓词{{1}},意思是&#34;子列表&#34; (或&#34;子序列&#34;)但更重要的是,这意味着每个您提供的描述的子列表,这是一个连续的子列表(不能有任何&#34;间隙&#34;在它)。
现在我们可以分解你的条款:
sl/2
这说明空列表是空列表的连续子列表。这是事实,这是一个有效的事实。
sl([], []).
如果sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
是[X|Ys]
的连续子列表,则 [X|Xs]
是Ys
的连续子列表。这种关系不为真。这里真实的是: Xs
是[X|Ys]
的连续子列表,如果[X|Xs]
是Ys
的连续前缀子列表 } 的。也就是说,Xs
不仅需要是Ys
的子列表,而且它只需要从列表的开头而不是列表中的某个位置。这是一个线索,你需要另一个谓词,因为关系的含义是不同的。
如果Xs
是Ys
的子列表,那么 [_|Xs]
是Ys
的子列表。这似乎是真的。
如果我们只是调整到上面更新的定义,我们得到:
Xs
我在没有解释的情况下提供了subseq([], []).
subseq([_|Xs], Ys) :-
subseq(Xs, Ys).
subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
prefix_subseq(_, []).
prefix_subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
上面的定义,但我认为你可以弄明白。
现在产生:
prefix_subseq/2
定义子列表(或子序列)的一种有趣,紧凑的方法是使用| ?- subseq([a,b,c,d], R).
R = [a] ? a
R = [a,b]
R = [a,b,c]
R = [a,b,c,d]
R = [b]
R = [b,c]
R = [b,c,d]
R = [c]
R = [c,d]
R = [d]
R = []
(1 ms) yes
谓词:
append/2
这表示subseq(L, R) :- append([_, R, _], L).
是附加列表L
,_
和R
的结果。这个简单实现中的一个小缺陷是,您不止一次地获得_
,因为它以多种方式满足R = []
规则。
重新审视定义,您可以使用DCG来定义子序列,因为DCG非常适合处理序列:
append([_, R, _], L)
您可以使用% Empty list is a valid subsequence
subseq([]) --> ... .
% Subsequence is any sequence, followed by sequence we want, followed by any sequence
subseq(S) --> ..., non_empty_seq(S), ... .
% Definition of any sequence
... --> [] | [_], ... .
% non-empty sequence we want to capture
non_empty_seq([X]) --> [X].
non_empty_seq([X|T]) --> [X], non_empty_seq(T).
调用它:
phrase/2
我们可以稍微重新调整一下这个定义并使用常见的| ?- phrase(subseq(S), [a,b,c,d]).
S = [] ? ;
S = [a] ? ;
S = [a,b] ? ;
S = [a,b,c] ? ;
S = [a,b,c,d] ? ;
S = [b] ? ;
S = [b,c] ? ;
S = [b,c,d] ? ;
S = [c] ? ;
S = [c,d] ? ;
S = [d] ? ;
no
定义来使其更紧凑:
seq//1