Prolog 中列表的所有初始段

All initial segments of a list in Prolog

Q)找到给定列表 [1, 3, 6 ,9, 8] 的所有初始段。即 []、[1]、[1,3]、[1,3,6]

我被困在如何构造对段的递归调用上,我知道我必须使用追加函数但不确定如何将它们组合在一起,我有以下代码:

append([], L, L).
append([H|L1], L2, [H|L3]):-
  append(L1, L2, L3). 


segments([],[]).
segments([H|L1],R):-

不使用追加:

% Inc can be an empty list, if Lst is a list (empty or not)
increasing_list([], []).
increasing_list([_|_], []).

increasing_list(Lst, Inc) :-
    increasing_list_(Lst, Inc).

% Unify Inc with the current element (Head) of Lst
increasing_list_([Head|_Tail], [Head]).

% Add Head element from Lst to Inc
increasing_list_([Head|Tail], [Head|Inc]) :-
    % Loop through the elements in Lst
    increasing_list_(Tail, Inc).

swi-prolog 中的结果:

?- increasing_list([1, 3, 6 ,9, 8], Inc).
Inc = [] ;
Inc = [1] ;
Inc = [1,3] ;
Inc = [1,3,6] ;
Inc = [1,3,6,9] ;
Inc = [1,3,6,9,8]

请注意,@gusbro 的 append/3 解决方案以及 @brebs 的答案在给出初始列表的情况下效果很好,但是,两者都允许其他非列表解决方案。

?- L = [1|non_list], append(Segment, _, L).
   L = [1|non_list], Segment = []
;  L = [1|non_list], Segment = [1]
;  false.
?- L = non_list, append(Segment, _, L).
   L = non_list, Segment = []
;  false.

所以即使 non_list 也有效;这是一个尽可能远离列表的术语。通常会接受这种额外的不需要的概括,特别是如果你知道你永远不会依赖它。这也被称为术语的 list prefix

但如果您想确保只考虑列表,请使用 Prolog 的 -形式主义,这是许多领域的首选方法。

:- set_prolog_flag(double_quotes, chars). % to make "strings" readable

... --> [] | [_], ... . % any sequence

seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).

segment_of(Xs, Zs) :-
   phrase((seq(Xs), ...), Zs).

?- segment_of(Xs, "abc").
   Xs = []
;  Xs = "a"
;  Xs = "ab"
;  Xs = "abc"
;  false.
?- segment_of(Xs, non_list).
false.
?- segment_of("ab", L).
   L = "ab"
;  L = [a,b,_A]
;  L = [a,b,_A,_B]
;  L = [a,b,_A,_B,_C]
;  ...