2
$\begingroup$

I am trying to create a predicate in Prolog which allows me to delete all occurrences of X in a list L. I have the following code:

my_delete(X, L, R):- [] = L, [] = R
my_delete(X, L, R):- [Y|K] = L, [Y|M] = R, my_delete(X, K, M), (Y \= X)
my_delete(X, L, R):- [X|K] = L, [Y|M] = R, my_delete(X, K, R), (Y \= X)

And now, upon querying this following line, I receive no result, implying that no list R could be constructed so that it followed my requirements.

?:- my_delete(baz, [foo, bar, baz], X)

The construction works fine when the list I want to delete from didn't contain an occurrence of X in the first place, but not if it did. Why is my set of predicates insufficient? What needs to be changed?

$\endgroup$

1 Answer 1

4
$\begingroup$

There are some rules of thumb I follow when writing prolog. Two of them are:

  • Use dif instead of \=. From the reference manual: "To make your programs work correctly also in situations where the arguments are not yet sufficiently instantiated, use dif/2 instead."

  • Avoid unnecessary variables and always get rid of the "Singleton variables: [X]" error. It makes the code much more readable.

When I rewrite your code accordingly, your

my_delete(X, L, R):- [] = L, [] = R
my_delete(X, L, R):- [Y|K] = L, [Y|M] = R, my_delete(X, K, M), (Y \= X)
my_delete(X, L, R):- [X|K] = L, [Y|M] = R, my_delete(X, K, R), (Y \= X)

becomes

my_delete(A, [], []).
my_delete(X, [Y|K], [Y|M]):- my_delete(X, K, M), dif(X, Y).
my_delete(X, [X|K], R) :- my_delete(X, K, R).

which is not only concise and more readable, but it already seems to work.

As for your particular case, I think it has to do with the quote in the first rule of thumb above. Your X and Y are not sufficiently instantiated, so it is no surprise for me, that your program does not work correctly.

But the "dif vs. \=" issue is probably not a problem in this case. I replaced dif(X, Y) with X \= Y in the code I suggested above, and it still works. (It may be causing a problem in your code though. I don't know if this is the case.)

Just using dif instead of \= is not a solution either. After replacing the \=s with dif in your code, it still does not work correctly. If the element to be removed is at the last position, it does not work. my_delete(baz, [baz], X) fails, for example.

So what is the problem? It seems to me that you've made two mistakes in your last line. You've put an unnecessary (Y \= X). Line 3 was supposed to be the case in which L starts with X. So the inequality check there should probably be an equality check. And secondly, you probably shouldn't have splitted R into [Y|M].

You can try the code here: https://swish.swi-prolog.org/p/myClMmML.pl

Swish has a great debugger as well. Check out its help.

$\endgroup$
2
  • $\begingroup$ Thanks for your answer! I am obviously very new to Prolog and the entire paradigm itself. As such, I really appreciate general advice like this. $\endgroup$ Commented Apr 10, 2021 at 11:31
  • $\begingroup$ Then check out metalevel.at/prolog if you already haven't. (Chapters [0,13]) $\endgroup$
    – Alp
    Commented Apr 10, 2021 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.