Научная статья на тему 'Особенности написания функционально-логических параллельных программ с использованием языка FLOGOL'

Особенности написания функционально-логических параллельных программ с использованием языка FLOGOL Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
217
35
i Надоели баннеры? Вы всегда можете отключить рекламу.
i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Особенности написания функционально-логических параллельных программ с использованием языка FLOGOL»

Рис. 3

Полученные в ходе экспериментов результаты позволяют сделать следующие выводы относительно обучения перцептронной ИНС методом ВРШ:

1) увеличение коэффициента обучения Ь>1 позволяет ускорить процесс обучения;

2) устойчивость системы после увеличения коэффициента обучения до 16 значительно снижается, количество обучающих итераций напротив возрастает;

3) оптимальное значение коэффициента обучения находится в окрестности значения Ь=6.

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

Литература

1. Розенблатт Ф. Принципы нейродинамики. М.: Мир, 1965. 480 с.

2. Чернухин Ю.В. Нейропроцессоры. Таганрог: ТРТУ, 1994. 175 с.

3. Чернухин Ю.В. Нейропроцессорные ансамбли. Таганрог: ТРТУ, 1995. 149 с.

4. Уоссерман Ф. Нейрокомпьютерная техника: Теория и практика. М.: Мир, 10992. 240 с.

УДК 658.512

Н.Н. Карпова

Особенности написания функционально-логических параллельных программ с использованием языка БЪСЮОЬ

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

Пб

отношений, лежащие в основе предлагаемого языка функционально-логического параллельного программирования РЬСЮОЬ. Рассмотрены основные особенности программирования на языке РЬСЮОЬ.

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

В настоящее время большое распространение получили различные стили программирования, такие как объектно-ориентированное и визуальное, однако не спадает интерес и к другим видам программирования, таким как логическое, реляционное и функциональное. Интерес к функциональному программированию обусловлен следующими особенностями функциональных языков. Во-первых, более высокая степень абстракции, во-вторых, наиболее естественное представление задачи, в-третьих, меньшая длина исходного кода и, в-четвертых, что особенно важно, возможность реализации функциональных программ на параллельных машинах. Говоря о существующей практике применения функциональных языков, необходимо в первую очередь указать такую область, как интеллектуальные автоматизированные системы. Здесь функциональные языки прошли наиболее полную апробацию и признаны вполне адекватным инструментом.

К основным преимуществам функциональных языков по сравнению с императивными можно отнести следующие:

1) более высокий уровень написания программ: основное внимание уделяется алгоритмам, а не деталям его реализации;

2) компактная форма записи функциональных программ позволяет повысить производительность их написания;

3) функциональные языки свободны от побочных эффектов: существует единый механизм передачи параметров функции - "по значению";

4) функциональные программы легче верифицировать благодаря тому, что доказательства базируются на достаточно понятной концепции функции, а не на гораздо более сложной концепции Фон-Неймановской машины;

5) функциональные программы обладают естественным внутренним параллелизмом, в то время как явное задание параллелизма в императивных языках на Фон-Неймановских машинах может оказаться весьма затруднительным.

Каждое из этих свойств обусловлено неотъемлемо присущей функциональным языкам математической природой: конструкции функциональных программ являются действительно чистыми математическими функциями, описывающими Преобразование входных значений в выходные и не касающимися контекста, в котором они применяются. Эта особенность притягательна тем, что Функциональные программы являются своего рода иерархическими спецификациями, так часто употребляемыми в работах по технологии Программирования. В то же время вследствие того, что можно обратиться к °бычному математическому аппарату, формальное манипулирование Функциональными программами выполняется относительно просто как при Установлении их свойств, так и при преобразовании программ в более эффективные формы.

Языки функционального программирования можно условно разделить на три основные группы:

* продукционные языки;

* языки, основанные на аппарате ^.-исчисления;

* композиционные языки.

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

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

Наиболее представительной является группа функциональных языков, основанных на использовании аппарата Х-исчисления Черча. В эту группу входят языки Lisp [1], ML [2], Hope [3] и подобные им. Поскольку семантика языков функционального программирования может быть описана достаточно строго, эти языки явились идеальным объектом для отработки вопросов, связанных с типами данных и полиморфизмом, модульным программированием и т.п. Наиболее активно используется для этой цели языки Hope, Miranda, ML и его диалекты.

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

В языках композиционного программирования программы и данные строго разделены, что является серьезным преимуществом этих языков. Другим важным преимуществом композиционных языков является достаточно простая параллельная вычислительная модель, на основе которой возможна эффективная реализация этих языков. К недостаткам композиционных языков относятся отсутствие возможности описания функций высших порядков. Это частично компенсируется в языке ЯФС [4] при помощи средств описания схем функций. Идеи, заложенные в ЯФС, получили дальнейшее развитие в языке функционального программирования FUN [5]. Основополагающими свойствами языка FUN являются функциональность, композиционный характер определений и типизированность всех конструкций языка.

Несмотря на существенные различия всех функциональных языков, в большинстве из них можно выделить ряд наиболее общих черт. В качестве математической основы всех языков используется аппарат чистых математических функций. Все языки, за исключением FP, являются строго типизированными, при этом типы явно задаются пользователем или выводятся с помощью механизма вывода типов. Все языки обладают возможностями задания типов, определенных пользователем, а также средствами задания полиморфных типов. Практически все языки имеют возможность задания рекурсивных функций, а также функций высших порядков, т.е. функций, аргументами и значениями которых также являются функции. Наибольший интерес представляет система FP, а также языки ЯФС и FUN, т.к. в них возможно формирование новых функций из уже заданных с помощью специальных операций, называемых операциями композиции.

В предлагаем языке функционально-логического программирования FLOGOL сделана попытка объединения достоинств композиционных и ^-основанных функциональных языков. В язык введены операции композиции, в то же время язык позволяет описывать функции высших порядков, рекурсивные и полиморфные функции и создавать собственные типы данных.

2. Язык функционально-логического программирования FLOGOL

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

ТТ8

Известия ТРТУ

рекурсивных определений объектов, для задания на таких данных функций и отношений [6].

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

2.1. Теоретические основы языка FLOGOL

Математической основой для создания языка послужила теория направленных отношений [7,8].

В общепринятой практике п-арное отношение R(n) определяется как подмножество R(n) Di х D2 х xD, декартова произведения множеств Di, D2,

D„. В отличие от этого вводится понятие (ш, п )-арного направленного отношения или для сокращения d-отношения R(m,n) как некоторого неоднозначного в общем случае соответствия или отношения R(m,n): Di' х D21 х х Dm' =э Di" х D2” х х Dn" для соответствующих подмножеств Di', l<i<m и Dj", l<j<n. Множества {di | R(m,n) (d,) = {d2> и {d2 | R(m,n) (d,) = d2) называются областью определения и областью значений R(m,n) соответственно.

Допускаются также случаи т=0 или п=0 или шип равны нулю одновременно, Предполагая существование множества D(0)={1}, содержащего единственный элемент 1 - пустой кортеж со свойством ld=dl=d для любого кортежа d. Это дает Возможность рассматривать d-отношения в этих случаях как "обычные" т-арные отношения. Отношения R(0,m) можно трактовать как множества кортежей длины т.

Поскольку любой т-арный предикат однозначно характеризуется множеством Кортежей длины лп, на которых он принимает значение "истина", то вполне естественным является его представление в виде (ш,0)-арного d-отношения, область определения которого совпадает с областью истинности соответствующего предиката. Для ш=0 и п=0 существует всего два возможных d-отношения с пустым графиком и с графиком {(< , >)}, которые могут играть роль истинностных эначений false и true, соответственно. Функции и программы также представляют собой d-отношения с условием, что графики этих d-отношений являются Функциональными. Таким образом, понятие d-отношения не только обобщает общепринятое понятие отношения, но также является естественным при Представлении отображений (в том числе многозначных), какими являются Функции, программы и др.

Типизированное d-отношение определяется следующим образом: пусть Т с**етное множество сортов, которые обозначаются через t, ti, t2,..., t', t",..., и пусть каЖдому t из Т однозначно соответствует непустой носитель (множество данных) в'- Определим Dm = Di х Di х х Di как множество кортежей типа tit2 tn, Полагая для n=0 Dm ={1}, где 1-пустой кортеж (кортеж нулевой длины).

^ Типизированное d-отношение R типа (tn',tn") есть график соответствия из Dm' в

Арность d-отношения R определяется как пара длин п' и п" Последовательностей tn' и tn". Далее в обозначениях d-отношений указываются их аРность или тип в зависимости от того, что является более необходимым в соответствующем контексте.

В язык вводятся в качестве базисных следующие операции композиции

отношений: А, #, |.

Обозначим символами R' и R" существующие отношения, R обозначает новое °пРеделяемое отношение.

Последовательная композиция. Знак "А" означает последовательную °Мпозицию d-отношений:

К.дК" _ а)р)> | (Эу) <а, у> 6 Я'Л <у, р> € Я"}, где а - входной кортеж

отношения К', р • выходной кортеж отношения К", у - выходной кортеж отношения К1, являющийся одновременно входным кортежем отношения К".

В случае, если К' и Я"- типизированные ё-отношения типов (С,и) и (и,и") соответственно, то Я'АЯ" - типизированное (1-отношение типа (и',и"). Операция последовательной композиции ассоциативна.

Параллельная композиция. Знак "#" означает параллельную композицию отношений:

Я1#!*" = {<(а'а",Р'Р")> | <а',Р’> еЯ' & <а",Р"> е Я"}, где а’ и Р'- входные и выходные кортежн отношения Я', а а" и рп- входные и выходные кортежи отношения Я".

В случае, если Л' и Л"- типизированные (1-отношения типов (иГДпО и то Я'#Я" (1-отношение типа (иГ | 1п2\ и Г | Ьг"), где и' | 1П" обозначает конкатенацию последовательностей типов ь' и и". Операция # ассоциативна, а также является параллельной, т.к. возможно одновременное вычисление объединяемых этой операцией отношений.

Объединение ё-отношений. Знак "|" означает операцию объединения. Это обычное теоретико-множественное объединение, т.е. оно определяется как теоретико-множественное объединение (1-отношений Л' и Л" как графиков. Для случая объединения типизированных (1-отношений требуется равенство типов <1-отношений Я' и Я", причем результирующее (1-отношение имеет тот же самый тип. Операция объединения ассоциативна и коммутативна.

Все операции монотонны. Все отношения в языке допускают рекурсивное описание, т.е. могут быть описаны через самих себя.

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

Операции последовательной и параллельной композиции сохраняют свойство функциональности при их применении к функциональным ё-отношениям, а операция объединения нет. Если операция объединения (1-отношения применяется к ортогональным или совместным (1-отношениям, то она также сохраняет свойство функциональности для полученного (1-отношения [9, 10, 11]. Всякий конструктор является функциональным в интерпретации и любая пара различных конструкторов в интерпретации ортогональна. Любой класс (1-отношений, порожденный операциями композиции (1-отношений А, #, | относительно любого множества функциональных (1-отношений при условии, что операция | применяется только к ортогональным или совместным (1-отношениям, является функциональным.

2.2. Структура программы на языке РЬОСЮЬ. Понятие модуля и домена

В языке РЬОСЮЬ реализован принцип модульного программирования. Модуль является наиболее крупным "строительным блоком" при описании предметной области. Модули могут быть взаимосвязаны с помощью аппарата экспорта и импорта отношений. Импорт и экспорт реализованы в неявной форме. Это означает, что часть отношений внутри модуля является доступной извне (из другого модуля). При импорте отношения из другого модуля необходимо указывать квалифицированное имя данного отношения. Использование квалифицированного имени позволяет избежать проблем с совпадением имен

Раэных отношений. Программа на языке FLOGOL представляет собой один или Несколько связанных между собой через импорт-экспорт отношений модулей.

Необходимо провести четкое разграничение понятий модуля и домена. Каждый Модуль содержит хотя бы один домен. Имя такого домена является одновременно и иМенем модуля. Внутри такого домена может содержаться любое количество ПоДЦоменов, или доменов второго уровня. Каждый из этих доменов в свою очередь м°жет иметь вложенные домены. Уровень вложенности доменов не ограничен.

Для всех отношений, определенных в поддоменах, допустимо использование в Правой части имен всех отношений, описанных выше данного, вне зависимости от ГлУбины их вложенности. При этом действует ограничение, связанное с заданием Экспортируемых и неэкспортируемых отношений.

Модуль имеет следующую структуру. Он начинается с ключевого слова USES,

За которым следует список идентификаторов, т.е. имен других модулей, элементы Которых используются в данном модуле, за которым следует описание домена, являющегося головным в данном модуле.

Описание домена начинается с ключевого слова DOMAIN, за которым следует список внешних параметров домена и имя домена, которое для головного домена является одновременно именем модуля.

Описание элементов домена начинается ключевым словом BEGIN и Оканчивается ключевым словом END. Все отношения, которые не могут быть депортированы из данного модуля, описываются после ключевого слова WHERE.

2.3. Схемное задание отношений

Язык FLOGOL является "схематологическим" языком с высоким уровнем ретракции. Он обладает широкими возможностями для задания схем отношений.

^зык обладает возможностями параметризации доменов с помощью списка

Внешних параметров домена. Роль списка внешних параметров заключается в том, ' Я

Чт° с его помощью весь домен в целом может быть описан как схема, которая

3*висит от параметров. В список внешних параметров могут входить логические и

Натуральные параметры, а также функции, предикаты, отношения, т.е. практически

“се виды базовых конструкций языка.

Возможна также параметризация отдельных отношений в домене. Эта ПаРаметризация осуществляется с помощью списков входных и выходных ^Раметров отношения.

Схемы отношений могут быть заданы также с помощью существующих в языке конструкций IF-THEN-ELSE и CASE-OF. Эти конструкции синтаксически Подобны конструкциям условного перехода и выбора в других языках Программирования как функциональных, так и императивных, и несут ту же сМЫсловую нагрузку.

2.4. Базовые конструкции языка

Рассмотрим простую программу на языке FLOGOL.

DOMAIN {BOOLEAN В} D1

BEGIN

PREDICATE {CARDINAL N:PREDICATE P(#)} CP =

IF В THEN

IF N=0 THEN о

ELSE P | (N-l, P) CP

ELSEP

END

В данный модуль не импортируются отношения из других модулей, поэтому ОН не содержит конструкции USES. Модуль начинается с ключевого слова DOMAIN' За ним следует список внешних параметров домена.

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

В данном домене список внешних параметров состоит из единственного элемента. Элемент В описан как BOOLEAN, т.е. логический. Выражение этого вида может принимать два значения: TRUE (истина) и FALSE (ложь). Помимо логических параметров в список внешних параметров домена могут входить также параметры следующих видов:

CARDINAL. Выражение этого вида принимает значения из натурального ряда чисел.

PROPOSITION, или утверждение-факт. Вид 1 обладает арностью (0,0). OBJECT, или объект, имеет арность (0,1). Каждый объект может быть получен только одним конструктором. SET, или множество, также имеет арность (0,1).

TUPLE, или кортеж объектов, представляет собой упорядоченное множество объектов и обладает арностью (0, п).

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

TUPLE SET, или множество кортежей, имеет арность (0,п). На объект и на кортеж объектов налагаются требования функциональности. На множество подобное требование не налагается. FUNCTION, или функция, понимается как классическая математическая функция.

TUPLE FUNCTION является расширением классического понятия функции. Это функция, которая возвращает не одно значение, а кортеж значений. На этот подвид также налагается требование функциональности.

Определение отношения RELATION соответствует данному в разделе 2.1 определению направленного отношения.

Все базовые конструкции языка могут рассматриваться как отношения с наложенными на них ограничениями.

За списком внешних параме!ров следует имя домена (D1). Идентификатор должен начинаться с заглавной буквы, за которой может следовать любая последовательность букв и цифр.

Тело данного домена содержит единственный элемент - предикат с именем СР. Схема отношения, определямая этим предикатом, задана с помощью конструкции IF -THEN - ELSE. Спецификация входов предиката СР, заключенная в круглые скобки, содержит два входных параметра. Диапазон первого параметра вида CARDINAL не ограничен. Вторым параметром предиката СР является предикат Р, спецификация входов которого определена с помощью символа #, который означает то, что на входах данного предиката может быть любое отношение арности (0,1). В языке есть также символ для обозначения любого отношения арности (0,п) - *.

Предикат СР описан рекурсивно, при его описании использована единственная операция композиции - объединение.

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

Описание элемента домена может представлять собой определение элемента домена, как это показано в примере, либо его объявление.

Рассмотрим конструкции языка, используемые в объявлениях и определениях элементов домена:

Условие, которое может быть представлено:

1. С помощью операции отношения над целочисленными арифметическими выражениями (>, <, =, £, £).

2. Логической константой.

3. Идентификатором логического параметра.

4. В виде описания логического параметра, взятого из другого модуля, с задаваемыми в данном модуле фактическими параметрами.

5. С помощью конструкции условного перехода IF - THEN - ELSE.

6. С помощью конструкции выбора CASE - OF.

Арифметическое выражение, которое может быть представлено:

1. Натуральным числом.

2. Идентификатором натурального параметра.

3. В виде описания натурального параметра, взятого из другого модуля, с задаваемыми в данном модуле фактическими параметрами.

4. При помощи встроенных в язык функций IN и OUT, возвращающих число входов и выходов отношения, имя которого задано в качестве параметра соответственно.

5. С помощью конструкции условного перехода IF - THEN - ELSE .

6. С помощью конструкции выбора CASE - OF.

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

1. Комбинаторное отношение арности (0,0), записываемое как <> или {<,>}, что обозначает соответственно пустое множество или пару пустых кортежей. Запись о в языке рассматривается как TRUE, а запись {<,>} - FALSE.

2. Нулификатор, или отношение арности (1,0), имеющее один вход и не имеющее выходов. Условное обозначение ->.

_>(,.0)о {<а>> |а е D}.

3. Генератор, или отношение арности (0,1), не имеющее входов и имеющее один выход. Условное обозначение <-.

{<,а> |а е D}.

4. Копирование, или отношение арности (1,2). Условное обозначение -<.

-<(| 2) о {<а,аа> | а е D}.

5. Слияние, или отношение арности (2,1). Условное обозначение >-.

-< (2,1)о {<аа,а> |а е D}.

6. Пересечение, или отношение арности (2,2). Условное обозначение ><.

>< (2,2) о {<ар,ар> | а е D & р е D }.

7. Неравенство, или отношение арности (1,1). Условное обозначение -/-.

+ |и)о {<«,?> |ot€D&PeD}.

Элементарные комбинаторные константы 6 и 7 двойственны сами себе.

8. Тождество (идентичность), или отношение арности (1,1).Условное обозначение •

—(|,|) о {<а,а> | а е D }.

В языке реализована иерархическая система значений по умолчанию. Так, в списке внешних параметров домена любой параметр может быть либо просто °бъявлен, либо определен (с помощью логического или арифметического выражения, операций композиции и т.д. - в зависимости от вида параметра). При вызове отношения с фактическими параметрами, если фактическое значение такого Параметра указано, то оно заменяет собой определение, если же в списке Фактических параметров данный параметр отсутствует, то по умолчанию Принимается значение, вычисляемое с помощью определения. Естественно, в языке ^сть и набор стандартных значений по умолчанию для каждого вида (0 для вида

cardinal, true для вида boolean и т.д.).

Заключение

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

программирования. Часть описанных решений либо уже реализована, либо находится в стадии реализации.

ЛИТЕРАТУРА

1. Амамия М., Танака Ю. Архитектура ЭВМ и искусственный интеллект. М.: Мир, 1993.

2. Milner R. The Standard ML core language. Polimorphism: The ML/LCF/Hope Newsletter., vol. 2., no.2, October 1985.

3. Burstall R.M., MacQueen D.B., Sannella D.T. HOPE: An Experimental Applicative Language, 1st International LISP Conference, 1980.

4. Кутепов В.П. Организация параллельных вычислений на системах. М.: МЭИ, 1989.

5. Грызунов В.Б. Разработка и реализация системы функционального программирования для ПЭВМ / Автореферат дис.... канд. техн. наук. М., 1990.

6. Kutepov V., Falk V. Integrated tools for functional, logical and data-flow parallel programming and controlling parallel computations on computer systems // Proceed. Internal Conf. "Parallel Computing technolodgies". Novosibirsk, 1991.

7. Кутепов В.П., Фальк B.H. Направленные отношения: теория и приложения // Известия РАН. Техническая кибернетика. № 4, 1994.

8. Кутепов В.П., Фальк В.Н. Направленные отношения: теория и приложения // Известия РАН. Техническая кибернетика. № S, 1994.

9. Арефьев А.А., Кораблин Ю.П„ Кутепов В.П. Язык граф-схем параллельных алгоритмов и его расширения. // Программирование, 1981, №4, С. 14-25.

10. Фальк В.Н. Теоретические модели языков программирования и вопросы их структурной интерпретации. //Автореф. дисс.... канд. техн. наук. М.: МЭИ, 1978.

11. Кутепов В.П., Фальк В.Н. Функциональные системы: теоретический и практический аспекты // Кибернетика. 1979. № 1.

УДК 658.512

А.Г. Бенеташвили Некоторые аспекты реализации языка РЪОСОЬ как основы интегрированной системы функционально-логического программирования

В статье рассматриваются некоторые вопросы реализации интегрированной системы функционально-логического, программирования на основе языка FLOGOL. Дается описание промежуточного кода (внутреннего представления) программ, рассматриваются аспекты реализации интерпретатора языка на многопроцессорных машинах и вычислительных сетях.

1. Интегрированная среда функционально-логического программирования

i Надоели баннеры? Вы всегда можете отключить рекламу.