1

In Prolog, is it possible to check if the variable is certain value only if the variable is instantiated.

? - my_rule(X).

my_rule(X):-
    X = 4,
    write('continue'). 

Here I am trying to check if the X is 4, if the X is 4 then we continue, but I also want the rule to continue if the X is _, but when it is called with something else, like X is 3 then it should not continue.

So the results would look like this:

?- my_rule(X).

continue
true.

?- my_rule(4).

continue
true.

?- my_rule(3).

false.
Richard
  • 171
  • 1
  • 2
  • 13

3 Answers3

3

Have a look at var/1, atom/1 and ground/1:

  • var(X) is true if and only if X is a variable.

    ?- var(X), X= 1. X = 1.

    ?- X=1, var(X). false.

    ?- X=f(Y), var(X). false.

  • atom(X) is true if X is an atom.

    ?- atom(a). true.

    ?- atom(f(a)). false.

    ?- atom(X). false.

  • ground(X) is true if X is ground (does not contain variables).

    ?- ground(f(a)). true.

    ?- ground(f(X)). false.

The three predicates are deterministic (i.e. do not backtrack) and you can safely negate them.

Your code become something like this:

my_rule(4) :-
   % handle the 4 case
my_rule(X) :-
   var(X),
   % general case

I'm just not sure if this is, what you want. In most programs, there should be no necessity to handle the variable only case separately. Also be aware that such meta-logical tests are outside the scope of classical logic. If compare the queries X = 1, var(X) and var(X), X = 1, you can see that the conjunction is not commutative anymore but in logic A ∧ B = B ∧ A holds.

lambda.xy.x
  • 4,918
  • 24
  • 35
2

You can use double negation ( \+(\+(...)) ):

In your example:

my_rule(X):-
    \+(\+(X = 4)),
    write('continue'). 
gusbro
  • 22,357
  • 35
  • 46
  • May I ask you what would you do to check if it is `not 4`. So that it would work in every case except when the `X = 4` – Richard Dec 05 '18 at 15:54
  • 1
    @Richard: in that case you may use `\+(X==4)` – gusbro Dec 05 '18 at 16:09
  • In a lot of cases `dif/2` works better (it's more expensive because it postpones goals until it can decide if the arguments are equal or not). You can also use [`iso_dif/2`](https://stackoverflow.com/questions/26720685/how-to-define-and-name-the-corresponding-safe-term-comparison-predicates-in-is) which does no propagation but throws an exception in the case that cannot be decided immediately. – lambda.xy.x Dec 05 '18 at 18:07
1
my_rule(X):-
    check(X),
    write('continue').

% A fact used to check a value.
check(4).

% A predicate that checks if X is unbound, e.g. a variable.
check(X) :-
    var(X).

Verification of desired results.

?- my_rule(X).
continue
X = 4 ;
continue
true.

?- my_rule(4).
continue
true ;
false.

?- my_rule(3).
false.
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
  • Even though this answer looks cleaner, I have to accept the `gusbro` one since I have multiple cases of this example and that one fits better, but thank you for answering. – Richard Dec 05 '18 at 15:51
  • Can I asko you also how you would do it - check if it is `not 4`. So that it would work in every case except when the `X = 4` – Richard Dec 05 '18 at 16:43
  • 1
    @Richard Et tu, Brute? – Guy Coder Dec 05 '18 at 17:12