Testing term structure in has_type/2

After proagating the change to more code came across the example where the term could have different arity.

So this code (simplified for inclusion here) is wrong

error:hast_type(location,Location) :-
    must_be(ground,Location),
    Location = location(Location_name),
    (
        subsumes_term(location(_),Location)
    ;
        throw(error(type_error(location, Location), _))
    ),
    is_of_type(oneof([a,b,c]),Location_name).
error:hast_type(location,Location) :-
    must_be(ground,Location),
    Location = location(c,N),
    (
        subsumes_term(location(c,_),Location)
    ;
        throw(error(type_error(location, Location), _))
    ),
    must_be(nonneg,N).

because if location is location(c,1) the first clause would see it as an error when in fact it should not cause an error.

This code works

error:hast_type(location,Location) :-
    Location = location(Location_name), !,
    must_be(ground,Location),
    is_of_type(oneof([a,b,c]),Location_name).
error:hast_type(location,Location) :-
    Location = location(c,N), !,
    must_be(ground,Location),
    must_be(nonneg,N).
error:hast_type(location,Location) :-   
    throw(error(domain_error(location, Location), _)).

This throws the error only when the other choices fail. Because this pattern fits better with domain_error than type_error used domain_error.

Notice that the change follows the pattern

Head :-
   Goal,
   !,
   Rest of clause.

as noted in “The Craft of Prolog” by Richard A. O`Keefe (WorldCat) is section 3.10 Pruning Alternative Solutions and was noted here.