?- X = a, (Y) = X. X = Y, Y = a. -- why didn't this fail?


I am unsure why the expression doesn’t fail, given that X is not of the same “shape” as (Y).

thank you,


I think the pair of parens of “(Y)=X” is syntactically redundant, which
is ignored by the input reader.


I am illustrating, what is also a bind during a call pred(X, (Y)), if called with, say, pred(a,B), binds B=Y, and not B=(Y).

I think the inner pair of parens of “pred(X, (Y))” is syntactically redundant. Also I think prolog displays terms suppressing syntactically redundant parens, right ?

Right – but, its a structure, nevertheless, so i am wondering about it – why it was chosen be treated as redundant.


I am not sure what do you mean exactly by “shape”, because terms internally are represented in rooted labeled directed ordered graphs, in which parenthesis are not used any more as far as ordinal prolog computation are concerned. However I could share a question how the write predicate make output string displayed for such queries below, though one would say I should read the source of the write predicate, but I guess it refers to operator precedence declared by op/3 directives.

?- write(+(-(-(a), b), -(c))).
-a-b+ -c

?- write_canonical(-a-b+ -c).

Parenthesis on their own, in Prolog, have nothing to do with tuples, as in Python or Haskell. This confusion is very common, but I wonder how to avoid it other than telling people to read more and assume less.

In Prolog, one use for parenthesis is to override the operator precedence, as @kuniaki.mukai also explained . This is why a disjunction inside a larger conjunction is inside parentheses, like a, ( b ; c ), in contrast to a, b ; c. To see how they are different, you can use write_canonical/1 or display/1. To make it meta, you must wrap the term you are displaying in parentheses; otherwise, what Prolog reads is a goal with two arguments, not one.


?- display(a, b ; c). % what happens? what does it mean?

?- display((a, b ; c)).

?- display((a, ( b ; c ))).

There is a lot of code on Stackoverflow that uses parentheses for tuples, as if they create a flat data structure. They do not. And the data structure that you get is probably not what you expect.

?- display(a).

?- display((a)).

?- display((a, b)).

?- display((a, b, c)).

@kuniaki.mukai linked the other relevant page in the docs, too. I will paste the link in full just to make sure: https://www.swi-prolog.org/pldoc/doc_for?object=op/3

Pay attention to what this page says about the comma and parenthesized expressions.

1 Like

Now it makes sense to me …

If it were an algebraic thing then it wouldn’t make sense, since the variable is unbound and may or may not be a numerical value.


I have no idea what this means :slight_smile:

1 Like

If X =1, then (X) = X,

makes sense, mathematically speaking

But …

If X = giraffe, then (X) = X

is meaningless – this is not an algebraic expression with X bound to an atom.

But, if parenthesis are only there to order disjunctions, then (X) and X are indeed equivalent, no matter their bound value …


To override operator precedence. , and ; are only one example. There are many other, like a + b / c vs (a + b) / c.

Parentheses are also used for compound terms, as in name(arg1, arg2, ..., argN). There is also a good reason why you can’t have any space between the name and the opening paren.

1 Like

The question is why (X) binds correctly with an atom – e.g. (X) = a. X = a

What is the interpretation of the parenthesis here. And, the answer is, its ordering of disjunctions, which happen to not exist in this expression, hence the parenthesis is redundant.


None. Its even in the ISO core standard. The ISO core standard grammar specification has two lines, one line specifying what is parsed and the other line what is built. For example an infix is parsed/built:

exprn    = exprn-1 op exprn-1
op(X, Y) =     X         Y

And parenthesis are parsed/built:

exprn    = "(" expr1200 ")"
X        =         X

So the parenthesis disappear. They reappear during unparsing. They are inserted when necessary by the unparser. But they are not part of the built term. Therefore you also find:

?- write((((foo)))), nl.

To see whether two terms are the same “shape”, you can use write_canonical/1 or format/2 with the ~k conversion. For example, the following shows that ((y)+z), y+z, and +(y,z) are all the same term (same “shape”):

?- X = ((y)+z), Z=y+z, write_canonical(X), nl, write_canonical(Z),nl.
X = Z, Z = y+z.

There is also display/1 which in addition to everything else writes lists as compound terms. I am not sure if you can do this in any other way (unless you start playing with portray/1)

?- display([a]).

?- write_canonical([a]).

?- format("~k", [[a]]).

It is also the shortest one to type.

There was a thread on the topic some time ago but I cannot find it easily.