starblue правильно, но для того, чтобы правильно написать свою версию functor1/3
, я рекомендую вам рассмотреть «режимы», для которых она требуется:
- Проверьте существующий термин (т. Е. , а не переменная) на предмет его функтора / арности.
- Построить термин (присвоение его переменной) из описания функтора / арности.
- Все остальные режимы не имеют значения / неверны.
С учетом этих трех случаев попробуйте следующее. Во-первых, case (1): извлечь Functor и Arity из существующего термина:
functor1(Term, Functor, Arity) :-
\+ var(Term), !,
% inspect existing term
Term =.. [Functor|ArgList],
length(ArgList, Arity).
Обратите внимание, что мы исключаем другие случаи, если аргумент Term не является переменной с разрезом (!). Во-вторых, случай (2): построить термин из функтора и Arity:
functor1(Term, Functor, Arity) :-
var(Term),
atom(Functor),
number(Arity), !,
% build a term
length(ArgList, Arity),
Term =.. [Functor|ArgList].
Обратите внимание, что проверка режима, выполняемая подцелями до разреза (!), Включает в себя защиту (предварительное условие) для этого случая. Наконец, все другие случаи (т. Е. Те, в которых нам нужно создать термин, но не иметь функтора, арности или того и другого), недопустимы (3):
functor1(_Term, _Functor, _Arity) :-
throw('Arguments are not sufficiently instantiated.').
В качестве альтернативы, в этом последнем случае это целое предложение может быть опущено для достижения поведения, которое functor/1
возвращает false для оставшихся привязок аргументов, которые он будет охватывать.
Также обратите внимание, что в этой версии используются встроенные модули length/2
, var/1
, number/1
и atom/1
(среди прочих), которые присутствуют в SWI-PROLOG.