Is there a linter for prolog programs?

Or this way:

?- when( (nonvar(L); ground(LEN) ), ( ( nonvar(L), is_list( L); \+nonvar(L)), length( L, LEN))), L=[_|_], member( LEN, [2,3]).
false.

?- when( (nonvar(L); ground(LEN) ), ( ( nonvar(L), is_list( L); \+nonvar(L)), length( L, LEN))), member( LEN, [2,3]).
L = [_, _],
LEN = 2 ;
L = [_, _, _],
LEN = 3.

Because is_list( [_|_]) is false.

I really wish there was a way to turn this (variable age) off at will. It messes up with sorting and I have to special-code it every single time. In particular it’s a big pain when I’m trying to compare sets of clauses for (syntactic) equality, which I often have to do when I need to get rid of duplicate programs.

A surprise extra-logical bit of Prolog there.

Maybe we need a version of compare which returns the =@=, @<, … class of operators. But that leads to further questions. How would you (m)sort a list which contains A, A and B? Even numbervars cannot help here because the outcome depends on which variable was found first. But at least A and A would be grouped together at one side or the other.

This is indeed one way I use to get around the variable age in sorting. Another is to custom sort with predsort/3.

What you seem to be looking at is ordering that is based on the notion of variance?
If you just want equality, =@=/2 is your friend (or the more widely implemented equivalent variant/2).

If you want the real ordering,

is indeed the way to go. That doesn’t combine with sort/2, so you need predsort/3. If the purpose is maintaining a set, library(hashtable) could be an option. It uses variant_hash/2

Thanks. I’ve used =@=/2 as well as numbervars/3 and unifiable/3 with predsort/3 at different times for slightly different purposes. Somehow not all of them work all the time, but that’s I guess specific to my varied use cases.