0

Hi I am supposed to be learning Prolog and my teacher asked us to create a predicate. We are asked to make a predicate called compose which acts like zip but can take two input lists of uneven lengths. If one is bigger than the other, it simply appends the remaining excess elements of the larger list to the end of the result. The behavior as specified by the teacher is like this:

?- compose([a,b,c],[x,y,z],L).
L = [a,x,b,y,c,z]
?- compose([a,b,c],[x,y],L).
L = [a,x,b,y,c]
?- compose(L1,L2,[a,b,c]).
L1 = [] L2 = [a,b,c] ;
L1 = [a] L2 = [b,c] ;
L1 = [a,c] L2 = [b];
L1 = [a,b,c] L2 = []

My predicate so far :

my_compose([], [], []).
my_compose(List1, [], R):-
    append([], List1, R).
my_compose([], List2, R):-
    append([], List2, R).    
my_compose([Item1|Tail1], [Item2|Tail2], [Item1, Item2|R]):-
    my_compose(Tail1, Tail2, R).

But my output is somewhat different:

?- my_compose([a,b,c], [x,y,z], L).
L = [a, x, b, y, c, z] ;
L = [a, x, b, y, c, z] ;
L = [a, x, b, y, c, z].

?- my_compose([a,b,c], [x,y], L).
L = [a, x, b, y, c] ;
false.

?- my_compose(L1, L2, [a,b,c]).
L1 = [a, b, c],
L2 = [] ;
L1 = [],
L2 = [a, b, c] ;
L1 = [a, c],
L2 = [b] ;
L1 = [a],
L2 = [b, c] ;
false.

I would appreciate it deeply if anyone could explain what I am missing here?

Edit: The difference between this and shuffle is that shuffle is for two lists of the same length. Also, this should backward query.

1 Answers1

0

Let's look at this line:

my_compose([Item1|Tail1], [Item2|Tail2], [Item1, Item2|R]):- my_compose(Tail1, Tail2, R).

You are taking two elements from both lists and mixing them. So you new list will be like

list1 = [1,2,3,4] and list2 = [5,6,7,8]

and you trying to create list which will look like this.

Result = [4,8,3,7,2,6,1,5] .

Then you are calling append predicate here

my_compose(List1, [], R):- append([], List1, R). my_compose([], List2, R):- append([], List2, R).

Your R does not point to the List1 so how do you expect R(which gives you result) to be instantiated. You should write it like this:

my_compose(List1, [], R):- R = List1.

or a there is a simple way:

my_compose([], List2, List2).

Note you can't call append on empty list so this predicate fails , means prolog did not find any succesive branch.

Instead of this if we take only one element from one list like this:

my_compose([Item1|Tail1], List, [Item1|R]):- my_compose(Tail1, List, R).

Now what will happend? My first list will get empty after some time and my third argument will be like this [a,b,c|_someNumber] someNumber means a variable. So you define another predicate when your list is empty like this:

my_compose([], List2, List2).

This says that if my first list is empty then set my third argument equal to the second list.

So you see you have something like this [a,b,c|_someNumber] and that someNumber was passed as argument and at this point if i say _omNumber = list2 then i will get a list like this: ([a,b,c,x,y,z] So you need only this code:

my_compose([], List2, List2).
my_compose([Item1|Tail1], List, [Item1|R]):-
   my_compose(Tail1, List, R).
Luai Ghunim
  • 976
  • 7
  • 14