Here’s my attempt to define a “compare” function using Picat-style, and it behaves more-or-less as I’d expect if one of the arguments is uninstantiated:
comp(X,X,Comp) => Comp = '='.
comp(X,Y,Comp), X > Y => Comp = '>'.
comp(_,_,Comp) => Comp = '<'.
But if I want to use full term ordering:
comp2(X,X,Comp) => Comp = '='.
comp2(X,Y,Comp), X @> Y => Comp = '>'.
comp2(_,_,Comp) => Comp = '<'.
?- comp2(f(a), g(_), Comp).
Comp = (<). % this is what I'd expect
?- comp2(f(X), f(a), Comp).
Comp = (<). % I suppose this is OK, but it could also have Comp='=',X=a as a solution
From a “functional” point of view, the queries with comp2/3
have no meaning because uninstantiated variables aren’t part of functional programming. But uninstantiated variables can be used to get the “results” of functional computations. If I’m careful, then there’s no problem; but if I accidentally call comp2/2
with the wrong kind of arguments, it produces weird results.
Picat-style has the nice property that if none of the clauses match, I get an error. It would be nice if I also get an error if the arguments aren’t sufficiently instantiated – and I think that can be done by the “cut” checking that the trail hasn’t changed (that is, the head+guards haven’t caused anything to become instantiated).
EDIT:
Consider also these two variants, which ought to be equivalent to the code above:
comp3(X,Y,Comp), X=Y => Comp='='.
comp3(X,Y,Comp), X@>Y => Comp='>'.
comp3(_,_,Comp) => Comp='<'.
comp4(X,Y,Comp), X@>Y => Comp='>'.
comp4(X,Y,Comp), X@<Y => Comp='<'.
comp4(_,_,Comp), => Comp='='.