Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to improve this code that looks for a specific number in a list?

Tags:

prolog

I'm writing prolog code that finds a certain number; a number is the right number if it's between 0 and 9 and not present in a given list. To do this I wrote a predicate number/3 that has the possible numbers as the first argument, the list in which the Rightnumber cannot be present and the mystery RightNumber as third argument:

number([XH|XT], [H|T], RightNumber):-
    member(XH, [H|T]), !,
    number(XT, [H|T], RightNumber).
number([XH|_], [H|T], XH):-
    \+ member(XH, [H|T]).

so this code basically says that if the Head of the possible numbers list is already a member of the second list, to cut of the head and continue in recursion with the tail. If the element is not present in the second list, the second clause triggers and tells prolog that that number is the RightNumber. It's okay that it only gives the first number that is possible, that's how I want to use it.

This code works in theory, but I was wondering if there's a better way to write it down? I'm using this predicate in another predicate later on in my code and it doesn't work as part of that. I think it's only reading the first clause, not the second and fails as a result.

Does anybody have an idea that might improve my code?

sample queries:

?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X).
       X = 3
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X).
       X = 9
like image 294
Rose Avatar asked Feb 02 '26 22:02

Rose


1 Answers

First, the code does not work. Consider:

?- number(Xs, Ys, N).
nontermination

This is obviously bad: For this so-called most general query, we expect to obtain answers, but Prolog does not give us any answer with this program!

So, I first suggest you eliminate all impurities from your program, and focus on a clean declarative description of what you want.

I give you a start:

good_number(N, Ls) :-
        N in 0..9,
        maplist(#\=(N), Ls).

This states that the relation is true if N is between 0 and 9, and N is different from any integer in Ls. See clpfd for more information about CLP(FD) constraints.

Importantly, this works in all directions. For example:

?- good_number(4, [1,2,3]).
true.

?- good_number(11, [1,2,3]).
false.

?- good_number(N, [1,2,3]).
N in 0\/4..9.

And also in the most general case:

?- good_number(N, Ls).
Ls = [],
N in 0..9 ;
Ls = [_2540],
N in 0..9,
N#\=_2540 ;
Ls = [_2750, _2756],
N in 0..9,
N#\=_2756,
N#\=_2750 .

This, with only two lines of code, we have implemented a very general relation.

Also see logical-purity for more information.

like image 197
mat Avatar answered Feb 05 '26 11:02

mat