starblue is correct, but in order to write your version of functor1/3
properly, I recommend that you consider the 'modes' it requires:
- Inspect an existing term (i.e., not a variable) for it's functor/arity.
- Build a term (assigning it to a variable) from a functor/arity description.
- All other modes are irrelevant/incorrect.
With these three cases in mind, try the following. First, case (1): extract the Functor and Arity from an existing Term:
functor1(Term, Functor, Arity) :-
\+ var(Term), !,
% inspect existing term
Term =.. [Functor|ArgList],
length(ArgList, Arity).
Note that we exclude other cases if the Term argument is not a variable with the cut (!). Secondly, case (2): construct a Term from a Functor and an Arity:
functor1(Term, Functor, Arity) :-
var(Term),
atom(Functor),
number(Arity), !,
% build a term
length(ArgList, Arity),
Term =.. [Functor|ArgList].
Note that the mode checking performed by the subgoals prior to the cut (!) encapsulate the guard (precondition) for this case. Finally, all other cases (i.e., those where we need to construct a term, but don't have a functor, arity or either) are invalid (3):
functor1(_Term, _Functor, _Arity) :-
throw('Arguments are not sufficiently instantiated.').
Alternatively, for this last case, this whole clause can be omitted to achieve the behavior that functor/1
returns false for the remaining argument bindings it will cover.
Also note that this version relies on built-ins length/2
, var/1
, number/1
and atom/1
(among others), which are present in SWI-PROLOG.