How to compare/3 without surprises on non-ground terms?

It’s “compare if definitely able, else fail”. Throwing an error sounds excessive.

This seems reasonable:

compare_able(Comp, X, Y) :-
    compare_able_([X], [Y], Comp).

compare_able_([], Ys, Comp) :-
    compare_able_empty_(Ys, Comp).
compare_able_([X|Xs], Ys, Comp) :-
    compare_able_ys_(Ys, Xs, X, Comp).
    
compare_able_empty_([], =).
compare_able_empty_([_|_], <).

compare_able_ys_([], _, _, >).
compare_able_ys_([Y|Ys], Xs, X, Comp) :-
    (   X == Y
    ->  compare_able_(Xs, Ys, Comp)
    ;   ground(X),
        ground(Y)
        % Can compare with confidence
    ->  compare(C, X, Y),
        compare_able_map_(C, Xs, Ys, Comp)
    ;   nonvar(X),
        nonvar(Y),
        % Deconstruct
        X =.. Xs0,
        Y =.. Ys0,
        append(Xs0, Xs, Xs1),
        append(Ys0, Ys, Ys1),
        compare_able_(Xs1, Ys1, Comp)
    ).

compare_able_map_(<, _, _, <).
compare_able_map_(>, _, _, >).
compare_able_map_(=, Xs, Ys, Comp) :-
    compare_able_(Xs, Ys, Comp).

Results:

?- compare_able(C, X, X).
C = (=).

?- compare_able(C, a(X), a(Y)).
false.

?- compare_able(C, a(X), b(Y)).
C = (<).

?- compare_able(C, f(X,9,Y), f(Y,3,Y)).
false.

?- compare_able(C, f(X,9,Y), f(X,3,Y)).
C = (>).

?- compare_able(C, [1,2,X], [1,5,X]).
C = (<).