Prolog - Insert with facts
Question
I need to program a Predicate in Prolog that inserts an element in the indicated position and consequently modifies the position number of the rest of the elements in the list. What I've achieved is the next snippet of code that implements a Predicate which inserts an element at the end of the list. In the database sector, apart from LIST we've got also LONG that indicates the amount of elements in the list. At the end there's some code on my try to implement de predicate. Could anyone tell me what's wrong in there? I'm lost in here.
Domains
name=symbol
position=integer
element=integer
Database
list(name,position,element)
long(name,integer)
Predicates
nondeterm inserirf(element)
Clauses
list(b,1,1).
list(b,2,5).
list(b,3,8).
list(b,4,3).
long(b,4).
inserirf(V):-
long(b,X),
Y=X+1,
assertz(list(b,Y,V)),
assertz(long(b,Y)),
retract(long(b,X)),
long(b,Q),
list(b,Q,P),
write(P),nl.
Goal
inserirf(7).
My last try:
Predicates
nondeterm inserirl(nom,pos,element)
Clauses
list(b,1,1).
list(b,2,5).
list(b,3,8).
list(b,4,3).
list(b,5,10).
list(b,6,11).
long(b,6).
inserirl(L,Pos,E):-
long(L,Long),
Pos > Long,
NouLong = Long+1,
retract( long(L,Long) ),
assertz( list(L,Pos,NouLong) ),
assertz( long(L,NouLong) ).
inserirl(L,Pos,E):-
long(L,X),
XaPassar=X-1,
retract(llista(L,Pos,E)),
retract( long(L,X) ),
assertz( long(L,XaPassar) ),
inserirl(L, XaPassar,E),
long(L,Y),
Y2=Y+1,
retract( long(L,Y) ),
assertz( long(L,Y2) ),
assertz(llista(L,Pos,E)).
Goal
inserirl(b,3,9).
% 3 -> position
% 9 -> element
% b -> name of list
Hundreds thanks to any help.
Solution
Regarding "My last try":
- Why are you retracting the very list fact you are trying to (ultimately) assert?
- You have to shorten the list (that is, retract the last element & replace the length) before you can do the recursion (since it has to work on a shorter list).
Note: You'll end up spending a lot of time asserting & retracting long() facts, which you need to keep track of the length, but most of them will "cancel out". A more efficient approach would be to retract the original long(), then pass the length around as an argument, and only re-assert the new long when you're done. But get it working before you worry about optimizing!
OTHER TIPS
To get you started:
- Check to see if the inserted item goes at the end; if so, you can use your current code.
- If it DOESN'T go at the end: Remove (but remember!) the one currently at the end, recursively try to insert the new item, and then add the item you removed to the now-end (which can be done using your code).
Here's the base case:
inserirl(L,Pos,E):-
long(L,Len),
Pos > Len,
NewLen is Len+1,
retract( long(L,Len) ),
assertz( list(L,Pos,NewLen) ),
assertz( long(L,NewLen) ).
For the recursive case, change the facts to make the list 1 shorter, insert your new item into THAT, and then put back the item you removed onto the end.