Prolog - 列表中的序列

时间:2013-02-28 00:34:36

标签: prolog

我们希望构建一个获取列表L和数字N的谓词,如果N是列表L中最长序列的长度,则为真。     例如:

?- ls([1,2,2,4,4,4,2,3,2],3).
    true.

?- ls([1,2,3,2,3,2,1,7,8],3).
    false.

为此我建了 -

head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following

概念很简单 - 检查头部是否等于他的跟随,如果是,继续尾部并递减N

我检查了我的代码并且效果很好(忽略了N = 1) -

的情况
 ls([1,2,2,4,4,4,2,3,2],3).
true ; 
false . 

但是true答案并不是有限的,之后会有更多的答案,我怎么能让它回归有限的答案呢?

3 个答案:

答案 0 :(得分:3)

Prolog-wise,你有一些问题。一个是你的谓词仅在两个参数都被实例化时才起作用,这对Prolog来说是令人失望的。另一个是你的风格 - head/2并没有在[H|T]上添加任何内容。我也认为这个算法存在根本缺陷。我不认为您可以确定列表尾部不存在较长的序列,而不保留猜测长度的未更改副本。换句话说,@ Zakum指出的第二件事,我认为不会有一个简单的解决方案。

这就是我如何处理这个问题。首先是一个辅助谓词,用于获取最多两个值:

max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.

现在大多数工作sequence_length/2被委托给一个循环,除了空列表的基本情况:

sequence_length([], 0).
sequence_length([X|Xs], Length) :- 
    once(sequence_length_loop(X, Xs, 1, Length)).

once/1的调用确保我们只能得到一个答案。这将阻止谓词有效地生成带序列的列表,同时也使谓词具有确定性,这是您所希望的。 (它与切割良好的切割具有相同的效果)。

循环的基本情况:将累加器复制到输出参数:

sequence_length_loop(_, [], Length, Length).

归纳案例#1:我们有另一个相同值的副本。增加累加器并重复。

sequence_length_loop(X, [X|Xs], Acc, Length) :- 
    succ(Acc, Acc1), 
    sequence_length_loop(X, Xs, Acc1, Length).

归纳案例#2:我们有不同的价值。计算列表其余部分的序列长度;如果它比我们的累加器大,那就用它;否则,请使用累加器。

sequence_length_loop(X, [Y|Xs], Acc, Length) :- 
    X \= Y,
    sequence_length([Y|Xs], LengthRemaining),
    max(Acc, LengthRemaining, Length).

这就是我如何解决这个问题。我不知道它对你是否有用,但我希望你能从中收集一些东西。

答案 1 :(得分:2)

如何在最后一条规则中添加中断?

head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) .    % if the head equal to his following
ls(_,0) :- !.                                           % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!.         % if the head doesn't equal to his following

虽然我不是Prolog专家,但对我有用。

//编辑: btw。试试

14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.

对我来说看起来不对,没有检查N是否是最长的序列。或者我的要求是错误的?

答案 2 :(得分:2)

您的代码正在检查列表中是否存在至少一系列指定长度的元素。在访问列表时,您需要更多参数来保持搜索状态:

ls([E|Es], L) :- ls(E, 1, Es, L).

ls(X, N, [Y|Ys], L) :-
  (  X = Y
  -> M is N+1,
     ls(X, M, Ys, L)
  ;  ls(Y, 1, Ys, M),
     ( M > N -> L = M ; L = N )
  ).
ls(_, N, [], N).