Check if variable is empty or filled

Spenhouet picture Spenhouet · Jan 5, 2014 · Viewed 8.7k times · Source

I have the following problem:

prolog prog:

man(thomas, 2010).
man(leon, 2011).
man(thomas, 2012).
man(Man) :- once(man(Man, _).

problem:

?- man(thomas).
true ;        %i want only on true even if there are more "thomas" *working because of once()*

?- man(X).
X = thomas ;  %i want all man to be listed *isn't working*

goal:

?- man(thomas).
true ;

?- man(X).
X = thomas ;
X = leon ;
X = thomas ;

I do unterstand why this happens, but still want to get the names of all man. So my solution woud be to look if "Man" is initialized, if yes than "once.." else then... something like that:

man(Man) :- (->check<-,once(man(Man, _)); man(Man, _).

On "check" shoud be the code sniped that checks if the variable "Man" is filled.

Is this possible?

Answer

lurker picture lurker · Jan 6, 2014

One way to achieve this is as follows:

man(X) :-
    (nonvar(X), man(X, _)), !
    ;
    man(X, _).

Or, more preferred, would be:

man(X) :-
    (   var(X)
    ->  man(X, _)
    ;   once(man(X, _))
    ).

The cut will ensure only one solution (at most) to an instantiated X, whereas the non-instantiated case will run its course. Note that, with the cut, you don't need once/1. The reason once/1 doesn't work as expected without the cut is that backtracking will still come back and take the "or" condition and succeed there as well.