Search code examples
prolog

All initial segments of a list in Prolog


Q)Find all initial segments of the given list [1, 3, 6 ,9, 8]. i.e. [], [1], [1,3],[1,3,6]

I'm stuck on how to construct the recursive call to segments,I know I have to use an append function but not sure how to bring it all together, I have the following code:

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


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

Solution

  • Note that @gusbro's solution with append/3 as well as @brebs answer work well if the initial list is given, however, both permit also other solutions that are not lists.

    ?- 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.
    

    So even non_list works ; that is a term that is as far remote from a list as possible. Often such extra unwanted generalizations are accepted, in particular if you know that you will never rely upon it. Also this is know as a list prefix of a term.

    But if you want to be sure that only lists are considered, use Prolog's -formalism which is the method of choice in many areas.

    :- 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]
    ;  ... .