简体   繁体   中英

Prolog With Lists

I received this problem and I can't get it done, I don't know what I've done wrong, can someone help me ?

Write a predicate to add a value v after 1-st, 2-nd, 4-th, 8-th, … element in a list.

% add(L:list, E:Number, P:Number, C:number, H:List)
% add(i,i,i,i,o)

add([],_,_,_,[]).
add([_|T],E,P,C,[HR|TR]) :-
   P =:= C,
   HR is E,
   C is C+1,
   P is P*2,
   add(T,E,P,C,TR).
add([H|T],E,P,C,[H|TR]) :-
   P =\= C,
   C is C+1,
   add(T,E,P,C,TR).

Here's another possibility to define such a predicate. Whenever you are describing lists it is worthwhile to consider using DCGs since they yield easily readable code. First let's observe that there's only need for three arguments, namely the list, the element to be inserted and the list with the element already inserted at the desired positions. The arguments P and C are only needed for bookkeeping purposes so it's opportune to hide them inside the predicate. And since we're already about to redesign the predicates interface let's also give it a more descriptive name that reflects its relational nature, say list_e_inserted/3:

list_e_inserted(L,E,I) :-
   phrase(inserted(L,E,1,1),I).  % the DCG inserted//4 describes the list I

inserted([],_E,_P,_C) -->        % if the list L is empty  
   [].                           % the list I is empty as well
inserted([H|T],E,P,P) -->        % if P and C are equal
   {P1 is P*2, C1 is P+1},       % P is doubled and C is increased
   [H,E],                        % H is in the list I, followed by E
   inserted(T,E,P1,C1).          % the same holds for T,E,P1,C1
inserted([H|T],E,P,C) -->        % if P and C are
   {dif(P,C), C1 is C+1},        % different C is increased
   [H],                          % H is in the list I
   inserted(T,E,P,C1).           % the same holds for T,E,P,C1

Now let's see the predicate at work:

?- list_e_inserted([],10,I).
I = [].

?- list_e_inserted([1],10,I).
I = [1, 10] ;
false.

?- list_e_inserted([1,2],10,I).
I = [1, 10, 2, 10] ;
false.

?- list_e_inserted([1,2,3],10,I).
I = [1, 10, 2, 10, 3] ;
false.

?- list_e_inserted([1,2,3,4],10,I).
I = [1, 10, 2, 10, 3, 4, 10] ;
false.

The predicate also works in the other direction:

?- list_e_inserted(L,E,[1,10,2,10,3,4,10,5]).
L = [1, 2, 3, 4, 5],
E = 10 ;
false.

And the most general query also yields the desired solutions:

?- list_e_inserted(L,E,I).
L = I, I = [] ;
L = [_G23],
I = [_G23, E] ;
L = [_G23, _G35],
I = [_G23, E, _G35, E] ;
L = [_G23, _G35, _G47],
I = [_G23, E, _G35, E, _G47] ;
L = [_G23, _G35, _G47, _G53],
I = [_G23, E, _G35, E, _G47, _G53, E] ;
.
.
.

The main problem is that when a variable in Prolog gets instantiated you can't change the value eg increase the value so you need to use a new variable:

add([],_,_,_,[]).
add([H|T],E,P,C,[H,E|TR]) :-
   P =:= C, 
   C1 is C+1,
   P1 is P*2,
   add(T,E,P1,C1,TR).
add([H|T],E,P,C,[H|TR]) :-
   P =\= C,
   C1 is C+1,
   add(T,E,P,C1,TR).

Example:

?- add([1,2,3,4],10,1,1,L).
L = [1, 10, 2, 10, 3, 4, 10] ;
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM