List 如何在Prolog中获取所有连续的子列表/子集?

List 如何在Prolog中获取所有连续的子列表/子集?,list,prolog,substring,sublist,List,Prolog,Substring,Sublist,我想解决一个简单的问题,但即使我尝试了许多不同的方法,我也找不到解决方案。我使用的是SICStus Prolog(如果这很重要的话),我想得到一个列表的所有子列表/子集(我不知道哪个术语是正确的),它包含连续的元素。例如,如果我有列表[1,2,3,4],将sl/2谓词调用为sl([1,2,3,4],R)。,预期结果是: ? - sl([1, 2, 3, 4], R). R = [] ? ; R = [1] ? ; R = [1, 2] ? ; R = [1, 2, 3] ? ; R = [1,

我想解决一个简单的问题,但即使我尝试了许多不同的方法,我也找不到解决方案。我使用的是SICStus Prolog(如果这很重要的话),我想得到一个列表的所有子列表/子集(我不知道哪个术语是正确的),它包含连续的元素。例如,如果我有列表[1,2,3,4],将
sl/2
谓词调用为
sl([1,2,3,4],R)。
,预期结果是:

? - 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] ? ;

我应该如何修改谓词以获得所需的结果?

在Prolog中编写谓词时,需要考虑谓词的含义,或者它定义的关系。谓词给出非解的原因是您在谓词子句中混合了含义。它们的意思并不完全相同

谓词
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).
我提供了上面的
前缀\u 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
是附加列表
\u
R
\u
的结果。这个简单实现中的一个小缺陷是,您将多次获得
R=[]
,因为它以多种方式满足
append([\uu,R,[u],L)
规则

重新审视定义,您可以使用DCG定义子序列,因为DCG非常适合处理序列:

% 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).
你可以用
短语/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
定义使其更加紧凑:

subseq([]) --> seq(_) .
subseq([X|Xs]) --> seq(_), [X], seq(Xs), seq(_).

% alternatively: seq(_), seq([X|Xs]), seq(_).

seq([]) --> [].
seq([X|Xs]) --> [X], seq(Xs).

请注意,这称为a/子列表,但不是a!不确定您为什么不允许在
seq//1
中使用
[]
。空序列-这很常见。@false通常我同意。最初,我确实有
seq([])-->[]
作为基本情况,但没有
subseq([])-->
在此上下文中,在
seq//1
中允许
[]
会导致解决方案集中出现多个匹配的
[]
。从技术上讲,
[]
以多种方式满足原始谓词的定义,但我希望以“自然”的方式避免它。我在回答中将
seq//1
的名字改为
non_-empty_-seq//1
。使用误导性的名字是正常的吗?你可以说
{Xs=[||]},而不是seq(Xs)
。使用固定长度的
Xs
,这将大大提高效率。否则也可能(需要测量)。这很好。最自然的定义是:
non_empty_seq(Xs)-->{Xs=[||]},seq(Xs)。