Важным моментом является то, что мы хотим, чтобы эта программа работала правильно, какую бы структуру мы ей ни задали. Понятно, что одна из возможностей сделать это – обеспечить отдельное утверждение для каждого функтора, какой только можно представить. Но это работа, которую мы никогда не завершим, потому что существует бесконечно много различных функторов! Написать подобную программу можно, используя встроенные предикаты для работы со структурами произвольного вида. Здесь мы опишем некоторые из них – это предикаты functor, argи ' =..'. Мы опишем также предикат name, выполняющий операции над атомами.
Предикат
functorопределен таким образом, что
functor(T,F,N)означает, что
Т–
?- functor(f(a,b,g(Z)),F,N).
Z = _23, F = f
,N
?- functor(a+b,F,N).
F = +, N = 2
?- functor([a,b,c],F,N).
F =., N
?- functor(apple,F,N).
F = apple, N = 0
?- functor([a,b,c],'.',3).
нет
?- functor([a,b,c],a,Z).
нет
Прежде чем перейти к обсуждению предиката
arg,следует рассмотреть второй способ использования предиката
functor.В этом случае первый аргумент целевого утверждения
functor (Т, F, N)неконкретизирован. В этом случае два других аргумента должны быть конкретизированы, однозначно определяя функтор и число аргументов соответственно. Целевое утверждение такого вида всегда согласуется с базой данных, и в результате значением
Тстановится структура с указанными функтором и числом аргументов. Таким образом, это некоторый способ
Предикат functorиспользуется для создания структуры в основном тогда, когда нам надо получить «копию» некоторой уже существующей структуры с новыми переменными в качестве аргументов. Мы можем ввести для этого предикат копирование,использующий functorкак целевое утверждение:
копирование(Старая, Новая):- functor(Cтapaя,F,N), functor(Hoвaя,F,N).
В этом определении подряд используются два целевых утверждения functor.Если целевое утверждение копированиеимеет конкретизированный первый аргумент и неконкретизированный второй, то произойдет следующее. Первое целевое утверждение functorбудет соответствовать первому способу использования этого предиката (так как первый аргумент этого предиката конкретизирован). Следовательно, Fи Nконкретизируются, получив в качестве значений функтор и число аргументов этой существующей структуры. Второе целевое утверждение functorсоответствует второму способу использования этого предиката. На этот раз первый аргумент неконкретизирован, и информация, задаваемая Fи N, используется для создания структуры Новая.Эта структура имеет те же функтор и число аргументов, что и Старая, но ее компонентами являются переменные. Таким образом, возможен следующий диалог:
?- копирование(sentence(np(n(john)), v(eats)),X).
X = sentence(_23,_24)
Мы используем подобную комбинацию целевых утверждений functorв определении предиката reconsultв разд. 7.13.
Предикат argвсегда должен использоваться с конкретизированными первым и вторым аргументами. Он применяется для доступа к конкретному аргументу структуры. Первый аргумент предиката argопределяет, какой аргумент структуры необходим. Второй аргумент определяет структуру, к аргументу которой необходим доступ. Пролог находит соответствующий аргумент и затем пытается сопоставить его с третьим аргументом предиката arg.Таким образом, цель arg(N,T,A)согласуется с базой данных, если N-й аргумент Тесть А. Давайте рассмотрим несколько целевых утверждений с arg.
?- аrg(2,отношение(джон,мать(джейн)),Х).
X = мать(джейн)
?- arg(1,a+(b+c),X).
X =а
?- arg(2,[a,b,c],X).
X = [b,c]
?-arg(l,a+(b+c),b).
нет