Composite term not checked

I’m using: SWI-Prolog version 9.0.4

Why does this prolog program:

mycomp(a, b).

mypred(X):-
  X=mycomp(_, _).

Unify with ?- mypred(mycomp(z, w)). ?

I would have guessed that prolog would fail because z and w are not valid terms for mycomp. How would I have to rewrite my program for that to happen?

As discussed earlier, this is equivalent to:

mypred(mycomp(_, _)).

Since the underscore is an anonymous variable, it will match anything. In particular:

?- mycomp(z, w) = mycomp(_, _).
true.

I don’t quite get your question.

mypred(mycomp(_, _)).

Seems pretty obvious now that you wrote it :grin:

I don’t quite get your question.

What’s the elegant way of defining a predicate mypred(X) that only holds if X is a compound term mycomp(Z,W)?

The best I can think of now is something like:

mycomp(a, b).

mypred(mycomp(X, Y)):-
  mycomp(X, Y).

But it seems redundant to mention mycomp twice in the same predicate.

More generally, what’s the usual way that data encapsulation is done in prolog?

This does the equivalent of what your “best I can think of” code does:

mypred(mycomp(a,b)).

But, from your question, you seem to be asking something different. Did you mean this?

mypred(mycomp(_Z,_W)).

Hmmm… In the head of the predicate, mycomp(X,Y) is a Prolog term. In the body, it is a goal that you evaluate (or query…).

This is it:

mypred(mycomp(Z, W)).

But now both are “singleton variables” without any further constraints on them, so that will succeed for any Z and any W.

What kind of data encapsulation do you mean? This sounds like a technique, not an aim…

When you say “compound term”, you do realize this is really just a data structure and not a predicate? You can evaluate it as a predicate though, this is what happens if you put it in the place of a goal.

I still have a feeling this is a terminology confusion :sweat_smile:

EDIT: if you want to pass a predicate to a predicate, then you have define a meta-predicate. There is nothing special about it, really. For example, maplist is a meta-predicate, so you can do something like this:

?- maplist(plus(1), [2,3], Result).
Result = [3, 4].

This is equivalent to:

?- plus(1, 2, X), plus(1, 3, Y), Result = [X, Y].

Is that at all relevant for your question??

I suspect the OP is looking for:

mypred(X):-
  X=mycomp(_,_),
  X.

Possibly with a ground(X) in the middle if only explicit facts are required.

2 Likes

I think you should try the good old clause/2:

?- [user].
|: mypred(X) :- clause(X, true).
|: 
% user://1 compiled 0.00 sec, 1 clauses
true.

?- [user].
|: mycomp(a, b).
|: 
% user://2 compiled 0.00 sec, 1 clauses
true.

?- mypred(mycomp(z, w)).
false.

?- mypred(mycomp(A, B)).
A = a,
B = b.

(PS: where you see

% user://1 compiled 0.00 sec, 1 clauses

it means I’ve closed the input stream, hitting Ctrl+Z)

2 Likes

This is of course on Windows, on *nix it is Ctrl+D. Ctrl+Z will stop your process.

Is there any difference between

my_pred(X):- X.

and

my_pred(X):- clause(X, true).

?

One obvious difference is that this:

really just evaluates X. You can give it anything:

?- [user].
|: my_pred(X) :- X.
|: ^D% user://1 compiled 0.00 sec, 1 clauses
true.

?- my_pred(format("hello!~n", [])).
hello!
true.

If you use clause/2 with true as the second argument then this will certainly fail.

By the way, this definition:

looks a lot like call, doesn’t it? Even the docs say:

Note that a plain variable as a body term acts as call/1

They are so much different, like day and night…
The first form is using call/1, the second instead is using reflection, and this means that the first one executes the code, while the second one lists (kind of) it.

1 Like

I was so happy with Ian’s solution (and I’ve used it so much) that I made my own predicate to encapsulate it:

of_type(Variable, CompoundTerm):-
    Variable=CompoundTerm,
    CompoundTerm.

That I test with:

test_compound(a, b).

test_of_type(X, Y, Z):-
  of_type(X, test_compound(Y, Z)).
?- test_of_type(a, b, c).
false.

?- test_of_type(a, X, Y).
false.

?- test_of_type(test_compound(X, Y), X, Y).
X = a,
Y = b.

?- test_of_type(test_compound(_, _), X, Y).
X = a,
Y = b.

?- test_of_type(test_compound(z, w), X, Y).
false.