Агенты Интернет

Одной из основных областей применения Акторного Пролога являются исследование и разработка так называемых агентов Интернет. Агентами Интернет называют программы, которые автоматизируют сбор и анализ данных в Интернет, созданные для решения задач конкретного пользователя (или группы пользователей). То есть агенты Интернет соотносятся с универсальными поисковыми системами примерно как программы, написанные под заказ, и универсальные системы управления базами данных.

Акторный Пролог реализует основное преимущество логических языков в этой области, а именно то, что идеология и парадигма программирования Пролога (поиск по дереву в глубину с возвратом) достаточно точно соответствуют гипертекстовой структуре Сети и поведению человека при поиске информации в пространстве Интернет. Пролог является одновременно мощным средством синтаксического анализа текстов, языком запросов и универсальным языком программирования. В дополнение к этому Акторный Пролог обладает операционной семантикой, приспособленной для корректного с математической точки зрения логического программирования в динамической среде Интернет.

В этой главе мы рассмотрим использование логических акторов, параллельных процессов, а также некоторых предопределённых классов Акторного Пролога для логического программирования агентов Интернет.

Рассмотрим пример Web_1.A в каталоге Web.

Пример 1. Логическое представление HTML.

В данной реализации Акторного Пролога основным средством извлечения данных из Интернет является предопределённый класс 'Receptor'. В этом классе реализованы предикаты, позволяющие получать данные из Интернет и преобразовывать их в термы Пролога различного вида. Рассматриваемый пример иллюстрирует использование предикатов get_parameters, get_text, get_references и get_trees.

-------------------------------------------
-- An example of Actor Prolog program.   --
-- (c) 2002, Alexei A. Morozov, IRE RAS. --
-- Retrieving Web information.           --
-- Logical representation of HTML data.  --
-------------------------------------------
project: (('Web1'))
-------------------------------------------
class 'Web1' specializing 'Receptor':
--
location         = "http://www.cplire.ru";
max_waiting_time = seconds(12);
revision_period  = days(3);
attempt_period   = hours(1);
tags             = ["FONT","P"];

Слот location содержит адрес ресурса Интернет. Допускается использование адресов HTTP, FTP, а также имён файлов на локальном компьютере. Слот max_waiting_time содержит максимальное время ожидания отклика от сервера. Если время ожидания превысит указанный предел, ресурс будет считаться временно недоступным. Слот revision_period содержит интервал времени, в течение которого Акторный Пролог обязан выявить возможное изменение указанного ресурса Интернет в будущем. Слот attempt_period содержит период времени, через который Акторный Пролог будет пытаться обратиться к ресурсу, если этот ресурс временно недоступен. Слот tags будет рассмотрен позже, когда мы будем обсуждать предикат get_trees.

--
w1      = ('Report',
                title="Parameters",
                background_color='Yellow',
                x=0,
                y=0,
                width=40,
                height=10);
w2      = ('Report',
                title="Text of Resource",
                background_color='Cyan',
                x=40,
                y=0,
                width=40,
                height=10);
w3      = ('Report',
                title="Links of Resource",
                text_color='Magenta',
                x=0,
                y=10,
                width=40,
                height=15);
w4      = ('Report',
                title="Resource Structure",
                text_color='Blue',
                x=40,
                y=10,
                width=40,
                height=15);

Это текстовые окна, в которые будет выводиться информация, полученная из Интернет.

--
[
goal:-!,
        Parameters== ?get_parameters(),
        w1 ? clear,
        write_parameters(Parameters),
        --
        Text== ?get_text(),
        w2 ? clear,
        w2 ? write(Text),
        --
        List== ?get_references(),
        w3 ? clear,
        write_references(1,List),
        --
        Structure== ?get_trees(),
        w4 ? clear,
        write_tag_structure(0,Structure).
--
write_parameters(entry(URL,D,T,_,S)):-
        w1 ? writeln("URL:  ",URL),
        write_date(D),
        write_time(T),!,
        w1 ? writeln("Size: ",S).
write_parameters(Error):-
        w1 ? writeln(Error).
--
write_date(date(Y,M,D)):-
        w1 ? writeln(
                "Date: ",Y,"-",M,"-",D).
--
write_time(time(H,M,S,_)):-
        w1 ? writeln(
                "Time: ",H,":",M,":",S).
--
write_references(N,[URL|Rest]):-!,
        w3 ? writef("%3d %s\n",N,URL),
        write_references(N+1,Rest).
write_references(_,_).
--
write_tag_structure(T,
                [block(Tag,List)|Rest]):-!,
        shift_text(T),
        w4 ? writeln("block \"",Tag,"\":"),
        write_tag_structure(T+1,List),
        write_tag_structure(T,Rest).
write_tag_structure(T,[Item|Rest]):-!,
        shift_text(T),
        w4 ? writeln(Item),
        write_tag_structure(T,Rest).
write_tag_structure(_,_).
--
shift_text(T):-
        T > 0,!,
        w4 ? write("   "),
        shift_text(T-1).
shift_text(_).
]
-------------------------------------------

Вот что программа вывела на экран:



Рис. 1.1. Логическое представление данных в формате HTML.

Рассмотрим каждое окно программы по порядку.

В окне "Parameters" программа вывела параметры указанного ресурса, полученные с помощью предиката get_parameters, а именно URL ресурса, дату и время последнего обновления ресурса, а также размер ресурса. Предикат вернул составной терм entry(URL, Date, Time, Attributes, Size). Значение четвёртого аргумента этого терма, Attributes, зависит от типа ресурса и в данном примере рассматриваться не будет.

В окне "Text of Resource" программа вывела текст в формате HTML, полученный из Интернет с помощью предиката get_text, без какой-либо дополнительной обработки.

В окне "Links of Resource" программа вывела список гиперссылок, обнаруженных в составе указанного ресурса. Список гиперссылок получен с помощью предиката get_references. Обратите внимание, что все обнаруженные ссылки приведены к полной форме. Там где это необходимо, в состав URL включён адрес сервера и каталог, в котором расположен соответствующий ресурс.

Четвёртое окно самое интересное. В нём программа напечатала данные, представленные в виде иерархии составных термов. Предикат get_trees, использованный для получения информации, автоматически преобразовал текст HTML в деревья. Предикат get_trees использует список имён, заданный в слоте tags класса 'Receptor', чтобы определить, какие именно теги HTML следует учитывать в ходе преобразования текста. При обнаружении в составе текста блока, тег которого указан в списке tags, создаётся составной терм вида block(Tag,List), где Tag - имя тега (большими буквами), а List - содержимое блока, также представленное в виде деревьев. Теги, не указанные в списке tags просто игнорируются. Гиперссылки, обнаруженные в составе текста, преобразуются в составные термы вида reference(URL,List), где URL адрес, а List содержимое блока гиперссылки, представленное в виде деревьев.

Обратите внимание, что исполнение программы на этом не закончилось. Акторный Пролог отвечает за корректность результатов работы программы даже в том случае, если исходные данные изменяются во времени. Следовательно, обязанностью программы является отныне и вовеки отслеживать возможные изменения указанного ресурса и обновлять данные, выведенные на экран. Чтобы остановить программу, нажмите кнопку .

Поддержка классической теоретико-модельной семантики программ, работающих в динамическом внешнем окружении, является главной отличительной особенностью и преимуществом Акторного Пролога по сравнению с другими логическими языками. Это достигается с помощью специальной стратегии логического вывода, основанной на логических акторах. Основные детали этой стратегии можно проиллюстрировать на следующих примерах.

Пример 2. Получение информации из нескольких источников.

Рассмотрим пример Web_3A.A в каталоге Web.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving information from several          --
--       Web resources.                               --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main':
--
actor1  = ('MyReceptor',
                location=
                        "http://www.cplire.ru/Lab144/"
                        "space/prolog.html",
                x=10,
                y=0);
actor2  = ('MyReceptor',
                location=
                        "http://www.comlab.ox.ac.uk/"
                        "archive/logic-prog.html",
                x=25,
                y=7);
actor3  = ('MyReceptor',
                location=
                        "http://www.cetus-links.org/"
                        "oo_prolog.html",
                x=40,
                y=14);
--
[
goal.
]
--------------------------------------------------------
class 'MyReceptor' specializing 'Receptor':
--
location;
max_waiting_time        = 0.0001;       -- 12.0;
revision_period         = 5.0;
attempt_period          = 1.0;
--
x;
y;
con     = ('Report',
                title=location,
                x,
                y,
                height=11,
                width=30);
--
[
goal:-
        Parameters== ?get_parameters(),
        write_parameters(Parameters).
--
write_parameters(entry(URL,Date,Time,_,Size)):-
        con ? writeln("URL:  ",URL),
        write_date(Date),
        write_time(Time),!,
        con ? writeln("Size: ",Size).
write_parameters(Error):-
        con ? writeln(Error).
--
write_date(date(Year,Month,Day)):-
        con ? writeln("Date: ",Year,"-",Month,"-",Day).
--
write_time(time(Hours,Minutes,Seconds,_)):-
        con ? writeln(
                "Time: ",Hours,":",Minutes,":",Seconds).
]
--------------------------------------------------------

Эта программа создаёт три экземпляра класса 'MyReceptor'. В соответствии с семантикой Акторного Пролога в каждом из этих миров создаётся актор goal. Этот актор получает параметры заданного ресурса Интернет и печатает их в соответствующем текстовом окне.



Рис. 2.1. Получение информации из нескольких источников.

Для того чтобы проиллюстрировать работу логических акторов, я специально задал очень маленькое значение слота max_waiting_time предопределённого класса 'Receptor' (на самом деле, это значение рекомендуется устанавливать равным нескольким секундам в зависимости от пропускной способности используемого канала Интернет). В результате доступ к указанным ресурсам был искусственно затруднён. Это привело к тому, что при обращении к третьему ресурсу был превышен лимит времени ожидания и предикат get_parameters вместо параметров ресурса вернул сообщение об ошибке lateness(MaxWaitingTime), где MaxWaitingTime превышенный лимит ожидания отклика от ресурса.

Интерпретатор запомнил эту неудачу и через некоторое время автоматически попытался обратиться к ресурсу ещё раз. Вторая попытка оказалась удачной. Интерпретатор вызвал повторное доказательство соответствующего актора, и полученные параметры ресурса были выведены на экран. После этого интерпретатор будет продолжать отслеживать состояние указанного ресурса Интернет, однако новое повторное доказательство рассматриваемого актора будет вызвано только в том случае, если параметры ресурса действительно изменятся, или если при очередной проверке ресурса он опять окажется временно недоступным.

Обратите внимание, что повторное доказательство актора, соответствующего рассматриваемому ресурсу, никак не отразилось на ходе доказательства двух других акторов. Преимуществом стратегии управления Акторного Пролога является возможность локальной модификации логических рассуждений, с сохранением тех результатов, математическая корректность которых не была нарушена вследствие изменения внешней среды.

Результаты доказательства двух других акторов в рассматриваемом примере оказались следующими. Первый актор успешно получил параметры при первом же обращении к указанного ресурсу и вывел их на экран. Параметры ресурса Интернет, запрошенные вторым актором, интерпретатор так и не сумел получить при искусственно заниженном значении max_waiting_time. Однако если ему это удастся в будущем, соответствующий актор будет доказан повторно, и параметры ресурса будут выведены на экран.

К сожалению, такие средства низкого уровня как текстовые окна не поддерживают логическую семантику программ. Практически это выражается в том, что на плечи программиста возлагается обязанность правильно организовать вывод на экран информации, полученной из Интернет. Если программист забудет вывести новые данные при повторном доказательстве актора, на экране так и останется устаревшая информация. Для того чтобы Акторный Пролог мог гарантировать математическую корректность всей информации, выведенной на экран, следует пользоваться средствами вывода более высокого уровня, а именно немодальными диалогами.

Пример 3. Вывод на экран информации из нескольких источников.

Рассмотрим пример Web_3A1R.A в каталоге Web. В этом примере информация, полученная логическими акторами, собирается в список при помощи резидента, и выводится на экран с помощью немодального диалога. Любое изменение параметров какого-либо ресурса приводит к автоматическому обновлению данных на экране, без каких либо усилий со стороны программиста.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Output of information retrieved from         --
--       several Web resources.                       --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main' specializing 'Dialog':
--
identifier      = "output";
--
actor1  = ('MyReceptor',
                location=
                        "http://www.cplire.ru/Lab144/"
                        "space/prolog.html",
                x=10,
                y=1);
actor2  = ('MyReceptor',
                location=
                        "http://www.comlab.ox.ac.uk/"
                        "archive/logic-prog.html",
                x=20,
                y=8);
actor3  = ('MyReceptor',
                location=
                        "http://www.cetus-links.org/"
                        "oo_prolog.html",
                x=30,
                y=15);
--
target_worlds   = [actor1,actor2,actor3];
results         = target_worlds ?? get_data();
--
[
goal:-
        show.
]
--------------------------------------------------------
class 'MyReceptor' specializing 'Receptor':
--
location;
max_waiting_time        = 2.0;
revision_period         = 5.0;
attempt_period          = 1.0;
--
x;
y;
con     = ('Report',
                title=location,
                x,
                y,
                height=10,
                width=30);
--
parameters;
--
[
goal:-!,
        Parameters== ?get_parameters(),
        Parameters == parameters.
--
get_data= Line
        :-
        parameters := entry(URL,Date,Time,_,Size),
        Line== ?format(
                "%d\t%s\t%s\t%s",
                Size,
                ?time_to_string(Time),
                ?date_to_string(Date),
                URL).
--
date_to_string(date(Year,Month,Day))=
        ?format("%d-%02d-%04d",Day,Month,Year).
--
time_to_string(time(Hours,Minutes,Seconds,_))=
        ?format("%d:%d:%d",Hours,Minutes,Seconds).
]
--------------------------------------------------------

Ниже приведено определение диалогового окна. Для вывода списка параметров используется элемент listbox с флагом UseTabStops. Элемент диалога напрямую присоединён к слоту results соответствующего экземпляра класса.

grid(80,25)
dialog_font("Arial",12,[])
dialog "output" (
          "",default,default,default,
          centered,centered,default)
     vbox(center)
          "Parameters of Web sites:"
          listbox['UseTabStops'](results,0000,45,4,[],[])
          button(close,"&Exit")
     end_of_vbox
end_of_dialog

Параметры элемента listbox(Content, Selection, Width, Height, InitialContent, InitialSelection) имеют следующее значение:

  1. Content - код доступа к содержимому элемента из программы - число, строка или имя слота. В рассматриваемом примере в качестве кода доступа задан слот results, поэтому значение этого слота будет автоматически выводиться на экран.
  2. Selection - код доступа к списку выбранных строк listbox. В данном примере выбор элементов списка пользователем не влияет на исполнение программы, поэтому этот код не используется.
  3. Width - ширина элемента (в буквах).
  4. Height - высота элемента (количество строк).
  5. InitialContent - содержимое элемента по умолчанию, список строк.
  6. InitialSelection - выборка элементов списка по умолчанию, некоторый список строк.

Программа откроет на экране диалоговое окно, в котором будет выведен список строк, вычисленный резидентом и переданный через слот results.



Рис. 3.1. Вывод на экран информации из нескольких источников.

Недостатком рассмотренного примера является то, что все три мира, в которых резидент доказывает функцию get_data, принадлежат одному процессу. Вследствие этого интерпретатор будет повторно доказывать все три актора при изменении любого из трёх ресурсов Интернет, чтобы упростить свою работу. Для того чтобы избежать лишних вычислений, мы разделим программу на несколько процессов, так чтобы каждому ресурсу Интернет соответствовал отдельный процесс.

Рассмотрим пример Web_3P1R.A в каталоге Web.

Пример 4. Сбор информации параллельными процессами.

Исходный текст этого примера практически полностью повторяет текст предыдущей программы. Изменены лишь конструкторы миров 'MyReceptor' в определении класса 'Main' (теперь это конструкторы процессов).

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving Web information by                --
--       concurrent processes.                        --
--------------------------------------------------------
class 'Main' specializing 'Dialog':
--
identifier      = "output";
--
actor1  = (('MyReceptor',
                location=
                        "http://www.cplire.ru/Lab144/"
                        "space/prolog.html",
                x=10,
                y=1));
actor2  = (('MyReceptor',
                location=
                        "http://www.comlab.ox.ac.uk/"
                        "archive/logic-prog.html",
                x=20,
                y=8));
actor3  = (('MyReceptor',
                location=
                        "http://www.cetus-links.org/"
                        "oo_prolog.html",
                x=30,
                y=15));
--
target_worlds   = [actor1,actor2,actor3];
results         = target_worlds ?? get_data();
--
[
goal:-
        show.
]
--------------------------------------------------------

Изменён также цвет фона диалогового окна.


grid(80,25)
dialog_font("Arial",12,[])
dialog "output" (
          "",default,default,default,
          centered,centered,green)
     vbox(center)
          "Parameters of Web sites:"
          listbox['UseTabStops'](results,0000,45,4,[],[])
          button(close,"&Exit")
     end_of_vbox
end_of_dialog

Программа выведет на экран те же самые результаты:



Рис. 4.1. Сбор информации параллельными процессами.

Обратите внимание, что во всех рассмотренных примерах список ресурсов Интернет был известен заранее, до начала работы программы. В последующих примерах будут рассмотрены приёмы получения информации из неизвестного заранее количества ресурсов.

Пример 5. Получение информации из неизвестного заранее количества источников.

Рассмотрим пример Web_N.A в каталоге Web. В этом примере актор goal при помощи предиката get_references получает список ссылок на статьи по Акторному Прологу, опубликованный на нашем сайте http://www.cplire.ru/Lab144. После этого он передаёт этот список в качестве параметра в рекурсивную процедуру inspect_pages. Эта процедура разматывает список адресов, получает параметры каждого ресурса при помощи предиката get_parameters и вычисляет дату последнего обновления указанных ресурсов. Вычисленная дата через защищающий слот max_date передаётся процессу 'Output', который выводит её на экран.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving information from arbitrary        --
--       number of Web resources.                     --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main' specializing 'Receptor':
--
location = "http://www.cplire.ru/Lab144/selected.html";
--
protecting: max_date;
--
dialog   = (('Output',
                location,
                max_date));
--
[
goal:-
        inspect_pages(?get_references,#).
--
inspect_pages([URL|Rest],Max1):-!,
        check_date(?get_parameters(URL),Max1,Max2),
        inspect_pages(Rest,Max2).
inspect_pages(_,max_date).
--
check_date(entry(_,Date2,_,_,_),Date1,Date2):-
        less(Date1,Date2),!.
check_date(_,MaxDate,MaxDate).
--
less(#,_):-!.
less(_,#):-!,
        fail.
less(Date1,Date2):-
        Date1 < Date2.
]
--------------------------------------------------------
class 'Output' specializing 'Dialog':
--
identifier      = "out";
recent_update;
--
location;
max_date;
--
txt             = ('Text');
--
[
goal:-!,
        show,
        check_date(max_date).
--
check_date(date(Year,Month,Day)):-!,
        recent_update==
                txt ? format(
                        "%04d-%02d-%2d",Year,Month,Day).
check_date(_).
]
--------------------------------------------------------

Взаимодействие процессов программы можно изобразить схематически с помощью диаграммы:



Рис. 5.1. Схема взаимодействия процессов.

Определение диалогового окна:

grid(80,25)
dialog_font("Arial",15,[])
padding(1.4,1.4)
dialog "out" (
          "",default,default,default,
          centered,centered,default)
     vbox(center)
          "Recent update of selected papers "
          "about the Actor Prolog:"
          table
               row
                    column
                         "Date"
                    end_of_column
                    column
                         text['AlignCenter']
                              (recent_update,7,1,"")
                    end_of_column
               end_of_row
               row
                    column
                         "Web Page"
                    end_of_column
                    column
                         text['AlignLeft']
                              (location,22,1,"")
                    end_of_column
               end_of_row
          end_of_table
          button(close,"&Exit")
     end_of_vbox
end_of_dialog

Результаты работы программы:



Рис. 5.2. Количество источников информации не было известно заранее.

Недостатком рассмотренной схемы является то, что обращение ко всем ресурсам Интернет осуществляется из одного актора. Следовательно, в дальнейшем изменение каждого ресурса будет приводить к повторному доказательству этого актора и повторному обращению ко всем остальным ресурсам. Для того чтобы избежать лишних вычислений, можно использовать другую схему, которая будет рассмотрена в следующем примере.

Пример 6. Использование прямых сообщений.

Рассмотрим пример Web_ND1R.A в каталоге Web. Взаимодействие процессов в этой программе происходит по следующей схеме:



Рис. 6.1. Использование прямых сообщений.

Процесс 'Main' получает список ресурсов, который необходимо проверить, и посылает процессу 'CheckPages' несколько прямых сообщений. Каждое прямое сообщение вызывает проверку одного из ресурсов. Параметры ресурса запоминаются в базе данных. Резидент, принадлежащий процессу 'Output', собирает список значений, записанных в базу данных, и посылает их экранному диалогу.

Результатом работы программы является список публикаций по Акторному Прологу на нашем сайте http://www.cplire.ru/Lab144 с датами последних обновлений:



Рис. 6.2. Собранная информация.

Рассмотрим подробнее текст программы.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving and output of information from    --
--       arbitrary number of Web resources.           --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main' specializing 'Receptor':
--
location = "http://www.cplire.ru/Lab144/selected.html";
--
receiver = (('CheckPages'));
--
out      = (('Output',
                data_source=receiver));
--
[
goal:-
        send_references(?get_references).
--
send_references([URL|Rest]):-!,
        receiver << check(URL),
        send_references(Rest).
send_references(_).
]
--------------------------------------------------------
class 'CheckPages' specializing 'Receptor':
--
location        = "";
--
registry        = ('Database');
--
[
goal.
--
check(URL):-
        store_parameters(URL,?get_parameters(URL)).
--
store_parameters(URL,Parameters):-
        registry ? retractall(page(URL,_)),
        registry ? append(page(URL,Parameters)).
--
get_data= Line
        :-
        registry ? find(page(_,entry(URL,Date,_,_,_))),
        Line== ?format(
                "%s\t%s",
                URL,
                ?date_to_string(Date)).
--
date_to_string(date(Year,Month,Day))=
        ?format("%d-%02d-%04d",Day,Month,Year).
]
--------------------------------------------------------
class 'Output' specializing 'Dialog':
--
identifier      = "out";
--
data_source;
--
results  = data_source ?? get_data();
--
[
goal:-
        show.
]
--------------------------------------------------------

Определение диалогового окна:

grid(80,25)
dialog_font("Times New Roman",14)
dialog "out" (
          "",default,default,default,
          centered,centered,'Cyan')
     vbox(center)
          "Selected papers about Actor Prolog:"
          listbox['UseTabStops'](results,0000,28,4,[],[])
          button(close,"&Exit")
     end_of_vbox
end_of_dialog

Cхема обработки информации, использованная в примере, не является логически чистой уже потому, что для хранения промежуточных результатов вычислений использована база данных (предопределённый класс 'Database'), операции с которой не имеют теоретико-модельной семантики.

Кроме того, в соответствии с семантикой Акторного Пролога акторы check, создаваемые в ходе обработки прямых сообщений check, исчезают сразу после окончания обработки сообщения. Следовательно, Акторный Пролог не будет отслеживать возможные изменения указанных ресурсов Интернет. Использование прямых сообщений само по себе в некоторых случаях также может нарушить логическую семантику программ.

Тем не менее, рассмотренная схема является практически полезной и часто используется в программах для автоматизации разовых операций поиска в Интернет. Её преимуществами являются простота и эффективность. Однако для создания математически строгих алгоритмов поиска и обработки информации следует использовать другие схемы, основанные на параллельных процессах, резидентах и потоковых сообщениях.

Пример 7. Получение информации из неизвестного заранее количества источников с помощью параллельных процессов.

Рассмотрим пример Web_NP.A в каталоге Web. Этот пример отличается от всех предыдущих тем, что для получения информации из каждого отдельного источника используется специальный процесс. Причём, поскольку количество источников информации неизвестно заранее, процессы создаются динамически, по мере необходимости. Для реализации динамического создания процессов будет использован один новый элемент языка, который мы ещё не рассматривали, а именно, так называемые "отключающие" слоты процессов.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving information from arbitrary        --
--       number of Web resources by concurrent        --
--       processes.                                   --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main' specializing 'Receptor':
--
location = "http://www.cplire.ru/Lab144/selected.html";
--
target_list;
--
chain    = (('ReceptorChain',
                suspending: target_list));
--
[
goal:-
        check_list(?get_references).
--
check_list([]):-!.
check_list(target_list).
]
--------------------------------------------------------
class 'ReceptorChain':
--
target_list;
rest_of_list;
--
chain    = (('ReceptorChain',
                suspending: target_list=rest_of_list));
--
location;
--
receiver = (('CheckPage',
                location));
--
[
goal:-
        check_list(target_list).
--
check_list([location]):-!.
check_list([location|rest_of_list]):-!.
]
--------------------------------------------------------
class 'CheckPage' specializing 'Receptor':
--
con     = ('Console');
--
[
goal:-!,
        write_parameters(?get_parameters),
        con ? nl.
--
write_parameters(entry(URL,Date,Time,_,Size)):-
        con ? writeln("URL:  ",URL),
        write_date(Date),
        write_time(Time),!,
        con ? writeln("Size: ",Size).
write_parameters(Error):-
        con ? writeln(Error).
--
write_date(date(Year,Month,Day)):-
        con ? writeln("Date: ",Year,"-",Month,"-",Day).
--
write_time(time(Hours,Minutes,Seconds,_)):-
        con ? writeln(
                "Time: ",Hours,":",Minutes,":",Seconds).
]
--------------------------------------------------------

В составе процесса 'Main' создаётся процесс 'ReceptorChain'. Особенностью класса 'ReceptorChain' является то, что он рекурсивный, то есть в составе мира 'ReceptorChain' создаётся новый экземпляр класса 'ReceptorChain' и так далее до бесконечности. Это позволяет программе создавать неограниченное число процессов, по одному на каждый исследуемый ресурс Интернет. Конечно, программа, использующая рекурсивный класс, могла бы зациклиться. Однако в нашем примере это не произойдёт благодаря отключающему слоту target_list.

Для объявления слота процесса "отключающим" используется ключевое слово suspending. Отключающий слот автоматически переводит соответствующий процесс в нерабочее состояние, если слот является несвязаной переменной, или значение слота равно константе #, и автоматически возвращает его в рабочее состояние при других значениях слота. Под нерабочим состоянием процесса подразумевается полное отсутствие каких-либо вычислений в процессе. Процесс не обрабатывает и не посылает никакие сообщения. С точки зрения декларативной семантики программы, отключённый процесс просто отсутствует, как будто соответствующего конструктора просто нет.

В конструктор процесса 'ReceptorChain' передаётся параметр target_list, значением которого в ходе исполнения программы станет список ресурсов Интернет, которые необходимо проверить. После этого отключающий слот разрешает создание соответствующего процесса. Созданный процесс получает список ресурсов, проверяет первый ресурс по списку, а хвост списка присваивает слоту rest_of_list. Хвост списка, в свою очередь, передаётся в следующий конструктор процесса 'ReceptorChain'. Таким образом, создаётся рекурсивная цепочка процессов, каждый из которых проверяет свой ресурс и печтает его параметры в текстовом окне. Последний из созданных процессов 'CheckPages' не присваивает никакого значения своему слоту rest_of_list, и развёртывание цепочки процессов на этом останавливается.

Для проверки параметров ресурса в составе каждого процесса 'ReceptorChain' создаётся вспомогательный процесс 'CheckPage', которому передаётся адрес ресурса. Созданную цепочку рекурсивных процессов можно изобразить графически с помощью принятых нами обозначений:



Рис. 7.1. Рекурсивная цепочка процессов.

Последний процесс в цепочке нарисован пунктирной линией, обозначающей состояние "отключён". Обратите внимание, что данная программа, в отличие от предыдущей, сохраняет математическую корректность в динамической среде Интернет. То есть при изменении количества исследуемых ресурсов будут создаваться новые процессы или, наоборот, будут отключаться процессы, созданные ранее. Все изменения в среде Интернет будут вызывать повторное доказательство соответствующих акторов и вывод новой информации на экран.



Рис. 7.2. Информация, полученная рекурсивными процессами.

Единственным недостатком рассмотренной программы является то, что для вывода полученной информации использовано средство низкого уровня - текстовое окно, которое не имеет логической семантики. В следующем примере для вывода информации использованы резидент и немодальный диалог.

Пример 8. Математически строгое извлечение и вывод информации.

Рассмотрим пример Web_NP1R.A в каталоге Web. Обсуждение примера мы начнём со схемы обработки информации.



Рис. 8.1. Схема обработки информации.

Основным элементом этого примера также является рекурсивное определение цепочки процессов 'ReceptorChain'. Однако, в отличие от предыдущей программы, в данном примере реализован вывод собранной информации через немодальный диалог. Для этого в конструктор процесса 'ReceptorChain' добавлен дополнительный параметр previous_receptors, в котором накапливается список вспомогательных процессов 'CheckPage', получающих информацию из Интернет. Процесс 'ReceptorChain', находящийся в конце цепочки, передаёт собранный список вспомогательных процессов в процесс 'Output', управляющий диалоговым окном.

--------------------------------------------------------
--       An example of Actor Prolog program.          --
--       (c) 2002, Alexei A. Morozov, IRE RAS.        --
--       Retrieving and output of information from    --
--       arbitrary number of Web resources by         --
--       concurrent processes.                        --
--------------------------------------------------------
project: (('Main'))
--------------------------------------------------------
class 'Main' specializing 'Receptor':
--
location = "http://www.cplire.ru/Lab144/selected.html";
--
target_list;
--
chain    = (('ReceptorChain',
                target_list,
                previous_receptors=[]));
--
[
goal:-
        check_list(?get_references).
--
check_list([]):-!.
check_list(target_list).
]
--------------------------------------------------------
class 'ReceptorChain':
--
suspending: target_list;
rest_of_list;
--
chain    = (('ReceptorChain',
                target_list=rest_of_list,
                previous_receptors=
                        [receiver|previous_receptors]));
--
previous_receptors;
--
location;
--
receiver = (('CheckPage',
                location));
--
all_receptors;
--
out      = (('Output',
                suspending: all_receptors));
--
[
goal:-
        check_list(target_list,all_receptors).
--
check_list([location],[receiver|previous_receptors]):-!.
check_list([location|rest_of_list],_).
]
--------------------------------------------------------
class 'CheckPage' specializing 'Receptor':
--
suspending: location;
--
parameters;
--
[
goal:-!,
        parameters == ?get_parameters.
--
get_data= Line
        :-
        parameters := entry(URL,Date,_,_,_),
        Line== ?format(
                "%s\t%s",
                URL,
                ?date_to_string(Date)).
--
date_to_string(date(Year,Month,Day))=
        ?format("%d-%02d-%04d",Day,Month,Year).
]
--------------------------------------------------------
class 'Output' specializing 'Dialog':
--
identifier              = "out";
background_color        = 'Yellow';
--
all_receptors;
--
results  = all_receptors ?? get_data();
--
[
goal:-
        show.
]
--------------------------------------------------------

В процессе 'Output' определён резидент, доказывающий предикат get_data во всех процессах переданного ему списка. Результатом этого становится список значений results, извлечённых из процессов 'CheckPage'. Этот список автоматически выводится на экран в диалоговом окне, определение которого приведено ниже:

grid(80,25)
dialog_font("Times New Roman",14)
dialog "out" (
          "",default,default,default,
          centered,centered,default)
     vbox(center)
          "Selected papers about Actor Prolog:"
          listbox['UseTabStops'](results,0000,25,4,[],[])
          button(close,"&Exit")
     end_of_vbox
end_of_dialog

Результаты программы:



Рис. 8.2. Результаты программы.

Итак, мы создали программу, которая математически корректным образом собирает и выводит на экран информацию из неизвестного заранее количества ресурсов Интернет. Обработка информации из различных источников осуществляется независимо друг от друга, с помощью параллельных процессов. Любое изменение параметров найденных ресурсов или даже изменение их количества, которое может произойти в будущем, вызовет автоматическую модификацию проведённых вычислений и вывод на экран уточнённых результатов поиска.

Оглавление