6.4.2. Функторы
Исчисление предикатов, ветвь логики, имеет тип данных, называемый функциональный символ (functional symbol). Функциональный символ имеет название, или функтор, за которым следуют аргументы. Аргументы записываются между круглыми скобками, и отделяются друг от друга запятыми. Говоря проще, они имеют в точности ту же форму записи, что и функции. Вот несколько примеров функциональных символов:
• author("Wellesley", "Barros", 1970)
• book( author("Peter", "Novig", 1960),"Artificial Intelligence")
• date("July", 15, 1875)
• entry("Prolog", "A functional language")
• index("Functors", 165)
• sunday
Последний пример показывает, что функциональный символ может вообще не иметь аргументов. Об этом сказали, давайте теперь посмотрим, как объявлять типы данных для новых функторов.
Пример вычисляет день недели для любой даты между годами 2000 и 2099. Он имеет следующие объявления доменов:
year = integer. year является синонимом integer. Использование синонимов делает вещи яснее.
day = sun; mon;tue; wed; thu; fri; sat; err. Этот аргумент имеет множество функциональных символов без аргументов. Каждый функциональный символ отделен от следующего точкой с запятой и отображает день недели.
month = jan; feb; mar; apr; may; jun; jul; aug; sep; oct; nov; dec. Ещё один домен (тип) с более чем одним функциональным символом.
month code = m(month, integer). Здесь, имеем функциональный символ с двумя аргументами.
numberOfDays=nd(integer);february. Другой тип с двумя функциональными символами: первый функциональный символ имеет один аргумент; второй не имеет ни одного.
Объявление списка:
% File newdomains.pro
implement newdomains
open core
constants
className = "newdomains".
classVersion = "".
class predicates
sum:(real*, real) procedure (i, o).
clauses
classInfo(className, classVersion).
sum([], 0) :- !.
sum([X|Xs], X+S) :- sum(Xs, S).
clauses
run():- console::init(),
sum([1, 2, 3, 4, 5, 6], A),
stdio::writef("The sum is %-4.0f", A).
end implement newdomains
goal
mainExe::run(newdomains::run).
% File: func.pro
% This program calculates the day of the week
% for the years between 2000 and 2099.
implement func
open core
constants
className = "func".
classVersion = "".
domains
year= integer.
day= sun; mon;tue; wed; thu; fri; sat; err.
month= jan;feb;mar;apr;may;jun;jul;aug;sep;oct;nov;dec.
month_code= m(month, integer).
numberOfDays= nd(integer); february.
clauses
classInfo(className, classVersion).
class predicates
monthCode:(string, month_code, numberOfDays)
determ (i, m(o,o), nd(o)) (i, m(o, o), o).
dayOfWeek:(integer, day) procedure (i, o).
calculateDay:( string Month, integer Day_of_the_month, year, day)
procedure (i, i, i, o).
clauses
monthCode("January", m(jan, 6), nd(31)) :- !.
monthCode("February", m(feb, 2), february ) :- !.
monthCode("March", m(mar, 2), nd(31)) :- !.
monthCode("April", m(apr, 5), nd(30)) :- !.
monthCode("May", m(may, 0), nd(31)) :- !.
monthCode("June", m(jun, 3), nd(30)) :- !.
monthCode("July", m(jul, 5), nd(31)) :- !.
monthCode("August", m(aug, 1), nd(31)) :- !.
monthCode("September", m(sep, 4), nd(30)) :- !.
monthCode("October", m(oct, 6), nd(31)) :- !.
monthCode("November", m(nov, 2), nd(30)) :- !.
monthCode("December", m(dec, 4), nd(31)) :- !.
dayOfWeek(0, sun) :- !.
dayOfWeek(1, mon) :- !.
dayOfWeek(2, tue) :- !.
dayOfWeek(3, wed) :- !.
dayOfWeek(4, thu) :- !.
dayOfWeek(5, fri) :- !.
dayOfWeek(6, sat) :- !.
dayOfWeek(_, err).
calculateDay(Month, MD, Year, D) :-
Y= Year-2000, % Берём две последние цифры Year.
monthCode(Month, m(_M, C), _), !, % Получаем код месяца.
S= Y+Y div 4+C+MD,
R= S mod 7, /* День недели как число между 0 (воскресенье) и 6 (суббота) */
dayOfWeek(R, D). % Получаем функциональный символ дня
calculateDay(_, _, _, err).
run():-
console::init(),
calculateDay("May", 3, 2005, R),
stdio::write("Day of the week: ", R), stdio::nl,
succeed(). % place your own code here
end implement func
goal
mainExe::run(func::run).
1Немецкий математик Эрнст Фридрих Фердинанд Цермело изобрёл запись множеств, которую мы использовали.