I want to get a list of atoms from my atom list based on given index_from i to index_to j. I tried many times but it did not return me the list but with a 'true' Below is my code, what do I miss? How do I get my output list instead of a 'true'.
% splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, INDEX_FROM, OUTPUTLIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
INPUT_LIST = INPUT_LIST,
S = S,
INDEX_FROM =:= INDEX_TO + 1,
write(LIST),
LIST = LIST.
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO,S,LIST) :-
INDEX_FROM < INDEX_TO + 1,
nth0(INDEX_FROM, INPUT_LIST, ELEMENT),
( INDEX_FROM =:= S ->
L = []
;
L = LIST
),
IF is INDEX_FROM + 1,
append([ELEMENT],L,NLIST),
splitList(INPUT_LIST,IF,INDEX_TO,S,NLIST),
!.
?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,0,L).
?- true.
My atom list: ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],
if index_from is 1, index_to is 3, I am expecting a returned output_list:
['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'] instead of a 'true',
On my base case, 'write(LIST) does write the expected list', Any idea?
You can write such a predicate without using the cut. Think about what your predicate should describe: a list, some indices for start, end and current position and a sublist of the first list that fits your start and end indices. So list_indices_sublist might be a good name. Now consider what cases you can have:
If the current position and the end position are the same, the head of the first list is the last to be in the sublist:
list_indices_sublist([X|_Xs],_Start,End,End,[X]).
If the current position is between the start and end positions the head of the first list is in the sublist. For the tails of both lists the relation (=the predicate) must hold too (=recursion):
list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
Pos #>= Start,
Pos #< End,
Nextpos #= Pos + 1,
list_indices_sublist(Xs,Start,End,Nextpos,Zs).
If the current position is smaller than the start position the head of the list is not in the sublist. For the tails, same as above:
list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
Pos #< Start,
Nextpos #= Pos+1,
list_indices_sublist(Xs,Start,End,Nextpos,Zs).
You might also consider providing a cleaner interface that hides the auxilary variable accounting for the current position in the list. Such a predicate would also be a good place for constraints that should hold for all three rules of list_indices_sublist/5, eg the start index must be smaller or equal to the end index. Let's call this predicate list_sublist_from_to/4. Putting it all together:
:- use_module(library(clpfd)).
list_sublist_from_to(L,S,Start,End) :-
Start #=< End,
list_indices_sublist(L,Start,End,1,S).
list_indices_sublist([X|_Xs],_Start,End,End,[X]).
list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
Pos #>= Start,
Pos #< End,
Nextpos #= Pos + 1,
list_indices_sublist(Xs,Start,End,Nextpos,Zs).
list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
Pos #< Start,
Nextpos #= Pos+1,
list_indices_sublist(Xs,Start,End,Nextpos,Zs).
Concerning the example you provided: You mean 1 to 4, right?
?- list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,4).
L = ['TYPE_INT','IDENTIFIER','OPEN_P','TYPE_INT'] ? ;
no
Or 1 to 3 and an answer with 3 elements in the sublist:
list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,3).
L = ['TYPE_INT','IDENTIFIER','OPEN_P'] ? ;
no
Note: If you want to start counting your list positions with 0 rather than 1 just change the 1 to 0 in the second goal of list_sublist_from_to/4
First, you should note that Prolog is not based on assignment, but unification. Then, for instance,
INPUT_LIST = INPUT_LIST,
is a tautology (unify the same term with itself, always true). You can safely remove them.
Second, your code has an additional parameter S
that has no clear role. Probably a residual detail of your attempted implementation, but then it should really be 'hidden', for instance:
% splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, OUTPUTLIST).
splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, LIST) :-
splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, 0, LIST).
Third, a cut at end of last clause of a predicate is totally useless, since all alternatives have already been tried - with success. Nothing left to be cut...
Fourth, since you use the builtin nth0/3, then note that a much simpler implementation could be
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
findall(E, (between(INDEX_FROM,INDEX_TO,I),nth0(I,INPUT_LIST,E)), LIST).
?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,L).
L = ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'].
But let's try to correct your code. Could be
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, 0, LIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
S < INDEX_FROM,
S1 is S+1,
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,[ELEMENT|LIST]) :-
S >= INDEX_FROM, S =< INDEX_TO,
nth0(S, INPUT_LIST, ELEMENT),
S1 is S+1,
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
splitList(_INPUT_LIST,_INDEX_FROM,INDEX_TO, S,[]) :-
S > INDEX_TO.
and will get you a similar result as the findall/3 based one-liner listed above. Note that instead of using append/3, the ELEMENT
is 'consed' into the 'output' parameter. See if you can spot the problem that is inherent with this code, specifically, try to understand why
?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,10,L).
false.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.