CAUTION: is it usually a mistake to distinguish between free and attributed variables, because variables can have several unrelated attributes (for example, some attributes are only for debugging purposes and should not affect the program behaviour at all). Correct code should check for the presence or absence of a particular attribute, and only use the free/1 test as a shortcut for detecting the absence of any attribute, e.g.
add_my_attribute_if_needed(X) :- free(X), % X has no attributes at all: add my one add_attribute(X, my_attribute). add_my_attribute_if_needed(X{my_attr:Attr}) ?- ( var(Attr) -> % X has attributes, but not my one: add it add_attribute(X, my_attribute) ; % X already has my attribute: do nothing true ).
Success: free(X). free(_abc). free(_). Fail: free(X{a}). suspend:(X>0), free(X). var(atom). var('Abc').