Search code examples
prologcombinatoricsgnu-prologprolog-defaulty

Prolog: how to do "check(a++b++c++d equals d++a++c++b) -> yes"


Let's define custom operators - let it be ++,equals

:- op(900, yfx, equals).
:- op(800, xfy, ++).

And fact:

check(A equals A).

I try to make predicate, let it be check/1, that will return true in all following situations:

check( a ++ b ++ c ++ d equals c ++ d ++ b ++ a ),
check( a ++ b ++ c ++ d equals d ++ a ++ c ++ b),
check( a ++ b ++ c ++ d equals d ++ b ++ c ++ a ),
% and all permutations... of any amount of atoms
check( a ++ ( b ++ c ) equals (c ++ a) ++ b),
% be resistant to any type of parentheses

return

yes

How to implement this in Prolog? (Code snippet, please. Is it possible? Am I missing something?)

Gnu-Prolog is preferred, but SWI-Prolog is acceptable as well.

P.S. Please treat code, as draft "pseudocode", and don't care for small syntax issues.

P.P.S '++' is just beginning. I'd like to add more operators. That's why I'm afraid that putting stuff into list might be not good solution.

Additionally

Additionally, would be nice, if queries would be possible (but, this part is not required, if you are able to answer to first part, it's great and enough)

check( a ++ (b ++ X) equals (c ++ Y) ++ b) )

one of possible results (thanks @mat for showing others)

X=c, Y=a

I am looking mostly for solution for first part of question - "yes/no" checking.

Second part with X,Y would be nice addition. In it X,Y should be simple atoms. For above example domains for X,Y are specified: domain(X,[a,b,c]),domain(Y,[a,b,c]).


Solution

  • Your representation is called "defaulty": In order to handle expressions of this form, you need a "default" case, or explicitly check for atom/1 (which is not monotonic) - you cannot use pattern matching directly to handle all cases. As a consequence, consider again your case:

    check( a ++ (b ++ X) equals (c ++ Y) ++ b) )
    

    You say this should answer X=c, Y=a. However, it could also answer X = (c ++ d), Y = (a ++ d). Should this solution also occur? If not, it would not be monotonic and thus significantly complicate declarative debugging and reasoning about your program. In your case, would it make sense to represent such expressions as lists? For example, [a,b,c,d] equals [c,d,b,a]? You could then simply use the library predicate permutation/2 to check for equality of such "expressions".

    It is of course also possible to work with defaulty representations, and for many cases they might be more convenient for users (think of Prolog source code itself with its defaulty notation for goals, or Prolog arithmetic expressions). You can use non-monotonic predicates like var/1 and atom/1, and also term inspection predicates like functor/3 and (=..)/2 to systematically handle all cases, but they usually prevent or at least impede nice declarative solutions that can be used in all directions to test and also generate all cases.