Using recursion method and returning a list in Prolog

Viewed 108

Given a list L1, position P, element A. I am trying to return a new list in which the element A is added at position P in the List L1 and return the answer in this way:

?- add_member(1,3,[2,3,4,5],A).

X=[2,3,1,4,5].

This is my code:

 add_member(X, P, [H|T], NewList) :-
  (P>1, 
    write('p>1 start | '),
    P1 is P-1, 
    add_member(X, P1, T, Newlist1), 
    NewList is [H, Newlist1]), 
    write('p>1 end ');
  (P=1, 
    write('p=1 start | '), 
    NewList is [X,H|T], 
    write('p=1 end | ')).

Here P is the position, X is the element to be inserted. I have used write('---') to know how the code works(like debug). This is its output(with error):

?- add_member(1,3,[2,3,4,5],x).
p>1 start | p>1 start | p=1 start | 
ERROR: Type error: `[]' expected, found `[1,4,5]' (a list) ("x" must hold one character)
ERROR: In:
ERROR:   [13] _22972 is [1,4|...]
ERROR:   [12] add_member(1,1,[4,5],_23016) at /mnt/c/Users/mill/Documents/q2.pl:1
ERROR:   [11] add_member(1,2,[3,4|...],_23058) at /mnt/c/Users/mill/Documents/q2.pl:5
ERROR:   [10] add_member(1,3,[2,3|...],x) at /mnt/c/Users/mill/Documents/q2.pl:5
ERROR:    [9] toplevel_call(user:user: ...) at /usr/lib/swi-prolog/boot/toplevel.pl:1117

Here, q2.pl is the name of the file and toplevel.pl is not accessible. I am using windows subsystem for linux (wsl).

How can I complete the code? Is there a concept that I am missing here?

1 Answers

is/2is a buildin predicate that requires that the second argument is a term that is arithmetically resolvable (examples: 3+6, 7*3).

In your example, you use NewList is [H, Newlist1] where the second argument is a list and not an arithmetic expression. Therefore you get a type error. You should use the matching operator = instead.

The second problem with your code is that [H, Newlist1] builds up a nested list (it is a list of length 2, the first element is H and the second is the list Newlist1. Here is the corrected version of your code:

add_member(X, P, [H|T], NewList) :-
  (P>1,
    write('p>1 start | '),
    P1 is P-1,
    add_member(X, P1, T, Newlist1),
    NewList = [H|Newlist1],
    write('p>1 end '))
  ;
  (P=1,
    write('p=1 start | '),
    NewList = [X,H|T],
    write('p=1 end | ')).

Two more remarks:

  • the insertion of an element at the first position of an empty list should be captured as well.

  • using disjunction (;) within a Prolog clause with more than a trivial alternatives code is not recommended (at least it should be used with care). Thus it is better to split your clause in two clauses (one for P=1 and one for P>1):

     add_member(X, 1, List, [X|List]).
     add_member(X, P, [H|T], [H|NewList]) :-
         P>1,
         P1 is P-1,
         add_member(X, P1, T, NewList).
    
Related