Компьютерный форум

Компьютерный форум (http://www.hardforum.ru/)
-   Prolog (http://www.hardforum.ru/f141/)
-   -   Visual Prolog 7.3 - Ликбез (http://www.hardforum.ru/t93619/)

Винитарх 07.01.2012 12:48

Visual Prolog 7.3 - Ликбез
 
Ликбез по фичам Visual Prolog для людей, знакомых с Прологом (любым).

1. Установите последний VIP Download free Visual Prolog: programming language, prolog compiler, development environment, linker
(там посередине красивая голубенькая кнопочка "Загрузить")
1.1 Зарегистрируйтесь (это бесплатно)
1.2 Можно сразу не региться, при первом запуске хеловорда он сам попросит зарегистрироваться.
1.3 Можно вообще не региться, тогда при каждом запуске будет Вам предложение о регистрации мозги компостировать.
2. Создайте консольное приложение: Project -> New -> Console application (radio button), вводим имя проекта желательно в англ. алфавите (оно же будет имя exe-шника), ибо в нац.алфавитах изредко на некоторых машинах бывают проблемы. Жмём Ok - создаётся консольный проект.
3. Никуда не глядя (глядеть то особенно пока нечего - в окне проекта нифига из исходников нет) запускаем проект на выполнение кнопочкой "Е" на панели инструментов (она же в меню Buid -> Execute).
4. Долго ждём компиляции. Первая компиляция всегда долго, потом очень быстро, так как будет перекомпилироваться только тот файл, где сделаны изменения.
5. После компиляции запускается проект на выполнение. Мы это видим по мелькнувшему окошку. Всё. Теперь можно открыть исходник main.pro и посмотреть что там внутри.
6. А внутри там по сути предикат run, который инициализирует консоль и всё:
Visual Prolog Код:
run():-
        console::init(),
        succeed(). % place your own code here
7. При первом запуске окошко консоли закрывалось самостоятельно, так как в коде нет никаких действий, кроме инициализации консоли. Для задержки закрытия окна после хэловорда вставим предикат ввода строки (он будет ждать нажатия Enter):
Visual Prolog Код:
run():-
        console::init(),
        console::write("Hello World"),
        _ = console::readLine().
8. Эффекта НЕзакрывания окна консоли можно добиться другим способом - запускать проект не кнопочкой "E" на панели инструментов, а через меню: Build -> Run in Window (Alt-F5). В этом случае Пролог создаёт батничек с внутренней паузой. Недостаток этого способа - надо всегда запускать батничек, а не сам exe-шник.
Кстати, сам exe-шник легко найти внутри проекта в папке EXE, там же будет и батничек, там же и dll-ки для exe-шника.

gromozeka 07.01.2012 13:02

Благодарю!
Щас убегаю, вечером поставлю, буду играться и вопросы задавать :) .

Винитарх 07.01.2012 13:22

Можно открыть класс console, тогда область видимости предикатов этого класса console распространится не весь main.pro, в котором мы разрабатываем наш проект.
Для этого надо в файле main.pro в директиве open указать через запятую открываемый класс:
open core, console
А также в предикате run() удалить все упоминания класса console (он же у нас уже открыт):
Visual Prolog Код:
run():-init(),
        write("Hello World"),
        _=readline().
Этим мы конечно не изменили функциональность, но улучшили читабельность что-ли.
Кстати, если наоткрывать много классов, то может так случиться, что в проге будут вызываться два предиката с одинаковыми именами, но из разных классов. В этом случае указывать имя класса перед предикатом надо, чтобы не было ambiguity - неопределённости.

Винитарх 09.01.2012 01:27

Предикаты и функции.
1. Всем известно как на Прологе выглядит предикат, опрежделяющий минимум двух чисел. Он выглядит так, как предикат minPredicate. Сделать из него функцию - плёвое дело. Выходной аргумент, а он у нас в предикате minPredicate - третий по счёту, недо вынести за скобки и направить прямо на него стрелку от предиката, тьфу - теперь уже от функции. В примере функция названа minFunction.
2. Для ввода с клавы чисел надо использовать предикат read. Он из класса console, но аналогичные предикаты есть в других классах, например в классе stdio пакета stream. Кстати, библиотека классов описана в хэлпе. Там дано описание всех предикатов, ну и доменов, констант. Единственное плохо - встроенные предикаты лично у меня отсутствуют в справке, но они есть на сайте visual-prolog в проложном wiki. Для ввода переменной с клавы в большинстве случаев не надо указывать тип переменной, VIP сам его вычисляет во время компиляции при анализе глобального потока данных. В данном примере тип - integer, так как и minPredicate и minFunction имеют в объявлении integer.
3. Очистка буфера клавиатуры с помощью console::clearInput() нужна перед предикатом ожидания Enter _=readline(). Дело в том, что предикат read читать-то читает, но за собой не подтирает буфер клавы, откуда он собственно и читает. Поэтому если перед _=readline() не очистить буфер, то никакого ожидания не будет и _=readline() считает что там есть, а там коды 10 и 13 от последнего ввода, и закроет окно приложения. Глазом моргнуть не успеете.
4. Режим детерминизма как minPredicate, так и minFunction, объявлен procedure, после которой следует патерн/шаблон потока параметров. i - input, o - output. Если шаблонов у предиката несколько, то следует их все перечислить через запятую. Потом дойдём до этого. Почему procedure? Потому что предикат при любых исходных данных (заданного типа) вернёт результат, причём результат будет единственным. Там отсечение стоит для единственности. Кстати, справа от типов аргументов указаны комменты с заглавной буквы. Эти комменты не обязательны, но зачастую они сильно облегчают жизнь.
Visual Prolog Код:
implement main
    open core, console

constants
    className = "main".
    classVersion = "$JustDate:  $$Revision:  $".

clauses
    classInfo(className, classVersion).

class predicates
minPredicate: (integer Arg1,integer Arg2, integer Minimum) procedure (i,i,o).
clauses
minPredicate(A,B,A) :- A<=B,!.
minPredicate(_,B,B).

class predicates
minFunction: (integer Arg1,integer Arg2) ->  integer Minimum procedure (i,i).
clauses
minFunction(A,B)=A :- A<=B,!.
minFunction(_,B)=B.

clauses
    run():-init(),
        X=read(),
        Y=read(),
        minPredicate(X,Y,Z),
        write("минимум1 = ",Z),nl,
        W=minFunction(X,Y),
        write("минимум2 = ",W),
        console::clearInput(),
        _=readline().
end implement main

goal
    mainExe::run(main::run).
Причешем программу сгруппировав разделы объявления предикатов class predicates в нашем классе main, вернее в его имплементации - main.pro. А также сгруппируеи клозы - clauses. В нашем примере клозы могут быть как ниже своих объявлений, так и выше. Однако по хорошему обявления должны располагаться выше клозов.
Кстати остальные файлы этого класса main можете наблюдать в окне проекта, они там на дереве висят.
Вот примерно так выглядит причёсанный файлик main.pro:
Visual Prolog Код:
implement main
    open core, console

constants
    className = "main".
    classVersion = "$JustDate:  $$Revision:  $".

class predicates
minPredicate: (integer Arg1,integer Arg2, integer Minimum) procedure (i,i,o).
minFunction: (integer Arg1,integer Arg2) ->  integer Minimum procedure (i,i).

clauses
classInfo(className, classVersion).
 
minPredicate(A,B,A) :- A<=B,!.
minPredicate(_,B,B).

minFunction(A,B)=A :- A<=B,!.
minFunction(_,B)=B.

clauses
    run():-init(),
        X=read(),
        Y=read(),
        minPredicate(X,Y,Z),
        write("минимум1 = ",Z),nl,
        W=minFunction(X,Y),
        write("минимум2 = ",W),
        console::clearInput(),
        _=readline().
end implement main

goal
    mainExe::run(main::run).
Параметрический полиморфизм.
1. Для того, чтобы наши предикат и функция работали не только с integer, но и с другими числовыми типами, а в VIP их много, можно конечно все типы перечислить в объявлении примерно так:
Visual Prolog Код:
minPredicate: (integer Arg1,integer Arg2, integer Minimum) procedure (i,i,o).
minPredicate: (real Arg1,real Arg2, real Minimum) procedure (i,i,o).
minPredicate: (unsigned Arg1,unsigned Arg2, unsigned Minimum) procedure (i,i,o).
...
Но это всё беспонтово. Так мы делали ещё в VIP5, а щас уже 7.3 заканчивается.
Сейчас можно вообще не указывать определённый числовой тип. Надо указать, что все аргументы имеют одинаковый тип. Этот тип обозначить какой-либо переменной, например X. Внутри объявления предиката пройдёт "унификация" всех вхождений этой переменной (и других переменных, если они есть), а значит связывание типов всех аргументов. Какой тип будет в конкретный момент времени - неважно, главное, что все три аргумента будут иметь одинаковый тип. Вот это и есть параметрический полиморфизм. Параметрический - потому что параметры предикатов полиморфны. Правда до этого мы их звали аргументами. Но это с какой стороны посмотреть, со стороны математической логики (аргументы) или со стороны теории программирования (параметры процедур и функций). В Прологе это всё скрестилось. Как хошь, так и называй.
2. Если тип параметров наших предикатов стал X, то как VIP определит какой КОНКРЕТНО тип переменной вводится с клавы? А никак. Но ведь надо как-то подсказать компилятору тип переменной в случае невозможности автоматического вывода типа. Для этого в Прологе есть предикат hasDomain(тип,переменная). Этот предикат не выполняется в runtime и не делает автоматическое доопределение типа "на лету". Этот предикат просто даёт информацию VIP-у на этапе компиляции о том, какого типа будет вводиться переменная.
В следующем примере функция закомментирована, а предикат вызывается с аргументами разных типов:
Visual Prolog Код:
implement main
    open core, console

constants
    className = "main".
    classVersion = "$JustDate:  $$Revision:  $".

class predicates
minPredicate: (X Arg1,X Arg2, X Minimum) procedure (i,i,o).
%minFunction: (X Arg1,X Arg2) ->  X Minimum procedure (i,i).

clauses
classInfo(className, classVersion).
 
minPredicate(A,B,A) :- A<=B,!.
minPredicate(_,B,B).

%minFunction(A,B)=A :- A<=B,!.
%minFunction(_,B)=B.

clauses
    run():-init(),
        hasDomain(integer,X),
        hasDomain(integer,Y),
        X=read(),
        Y=read(),
        minPredicate(X,Y,Z),
        write("минимум1 = ",Z),nl,
       
        hasDomain(real,A),
        hasDomain(real,B),
        A=read(),
        B=read(),
        minPredicate(A,B,C),
        write("минимум2 = ",C),
       
        console::clearInput(),
        _=readline().
end implement main

goal
    mainExe::run(main::run).

Винитарх 09.01.2012 13:11

Полиморфизм. Часть 2.
Пример, рассмотренный выше, имеет полиморфизм не только среди числовых доменов. Так как операция "<" применима и к символам, и к строкам, то предикаты minPredicate и minFunction могут работать и с этими символами, и со строками. Единственное, что надо не забывать - очищать буфер клавиатуры перед каждым вводом символов и строк (но это недостаток консоли, в GUI - этого гемора конечно нет):
Visual Prolog Код:
implement main
    open core, console

constants
    className = "main".
    classVersion = "$JustDate:  $$Revision:  $".

class predicates
minPredicate: (X Arg1,X Arg2, X Minimum) procedure (i,i,o).
minFunction: (X Arg1,X Arg2) ->  X Minimum procedure (i,i).

clauses
classInfo(className, classVersion).
 
minPredicate(A,B,A) :- A<=B,!.
minPredicate(_,B,B).

minFunction(A,B)=A :- A<=B,!.
minFunction(_,B)=B.

clauses
    run():-init(),
        hasDomain(integer,X),
        hasDomain(integer,Y),
        X=read(),
        Y=read(),
        minPredicate(X,Y,Z),
        write("минимум1 = ",Z),nl,
       
        hasDomain(real,A),
        hasDomain(real,B),
        A=read(),
        B=read(),
        minPredicate(A,B,C),
        write("минимум2 = ",C),nl,
       
        console::clearInput(),
        N=readchar(),
        console::clearInput(),
        M=readchar(),
        write("минимум3 = ",minFunction(N,M)),nl,
       
        console::clearInput(),
        S=readline(),
        console::clearInput(),
        W=readline(),
        write("минимум4 = ",minFunction(S,W)),nl,
       
        console::clearInput(),
        _=readline().
end implement main

goal
    mainExe::run(main::run).
Вот результаты:
Цитата:

56
4
минимум1 = 4

646.879
8078.0005
минимум2 = 646.879

я
ф
минимум3 = ф

пролог
питон
минимум4 = питон

aag 09.01.2012 14:39

Цитата:

Сообщение от Винитарх (Сообщение 611787)
Так как операция "<" применима и к символам, и к строкам,

И к спискам, что меня лично регулярно радует)))

Вопрос в тему: а как Вы писанину с консоли вытаскиваете?

Винитарх 09.01.2012 19:47

Цитата:

Сообщение от aag (Сообщение 611798)
И к спискам, что меня лично регулярно радует)))

Это должно было быть моим следующим постом. :744:
Цитата:

Сообщение от aag (Сообщение 611798)
Вопрос в тему: а как Вы писанину с консоли вытаскиваете?

Левой кнопью по иконке окошка (левый верхних угол) и в меню - Изменить. А там уже всё видно: Выделить всё, Копировать (Enter).

aag 09.01.2012 19:55

Цитата:

Сообщение от Винитарх (Сообщение 611926)
Это должно было быть моим следующим постом. :744:

Простите, Босс :942:



Цитата:

Сообщение от Винитарх (Сообщение 611926)
Левой кнопью по иконке окошка (левый верхних угол) и в меню - Изменить. А там уже всё видно: Выделить всё, Копировать (Enter).

Блин))) Благодарю...

D_K 10.01.2012 16:04

Винитарх, спасибо за тему. Обязательно поиграюсь с VIP :)

Винитарх 10.01.2012 23:12

Ну и вот то, о чём говорил aag, сравнение списков чего-угодно (написал только цель - предикат run(), всё остальное - без изменений):
Visual Prolog Код:
run():-init(),
        hasDomain(integer_list,X),
        hasDomain(integer_list,Y),
        X=read(),
        Y=read(),
        minPredicate(X,Y,Z),
        writef("минимум(%,%) = %",X,Y,Z),nl,
       
        hasDomain(string_list,A),
        hasDomain(string_list,B),
        A=read(),
        B=read(),
        writef("минимум(%,%) = %",A,B,minFunction(A,B)),nl,
       
        console::clearInput(),
        _=readline().
Результат:
Цитата:

[2,3,4,5]
[1,2,3,4,5,6,7]
минимум([2,3,4,5],[1,2,3,4,5,6,7]) = [1,2,3,4,5,6,7]

["abcdef","123"]
["абвгде","67"]
минимум(["abcdef","123"],["абвгде","67"]) = ["abcdef","123"]
Как видите, вывод форматированный, он есть во всех языках.
Списки сравниваются поэлементно. Если в одном списке элемент больше/меньше соответствующего элемента другого списка, то первый список считается больше/меньше. Если элементы списков одинаковые между собой, но первый список длинне второго (у него есть лишние элементы), то он и будет больше.

Ну вот, о параметрическом полиморфизме в VIP всё. Ещё есть дженерики (типы-аргументы), но о них потом.

Кстати, совсем забыл, точка входа в программу - предикат run(). Этот предикат можно перемещать в любое место раздела clauses файла main.pro. Главное, чтобы он был с режимом детерминизма - procedure, так как декларирован именно с этим режимом, это своеобразная дань операционной системе, так она принимает к выполнению только процедуры, ибо сама императивна до последнего байта своих мыслей.

Пока что мы работали только с процедурами. Если в цели надо запустить на выполнение предикат-непроцедуру, то надо сделать так:
Visual Prolog Код:
run():-init(),
           предикат_непроцедура(),!,
           _=readline();  % эта ветвь выполнится и, так как произошло отсечение, то точка входа во вторую ветвь будет вытолкнута из стека вызовов
           _=readline().  % эта вторая ветвь, она выполнится, если произойдёт откат в предикат_непроцедура()
При этом run() остался процедурой, у которой выполнится только одна ветвь: или первая, или вторая.

Следующим разом покажу работу со строками, текстовыми файлами, их ввод-вывод (самый простой).
Напомню. Так уж получилось с самого начала, что повествование пошло с расчётом на то, что читатель знаком с Прологом (любым). Поэтому основы, т.е. что такое предикат, факты БД, сопоставление с образцом (pattern matching) и поиск с возвратом (он же бактрекинг, он же backtracking) я не рассказываю. Но режимы детерминизма я покажу. Однако, если кому-то надо пояснить суть предикатов, сопоставления с образцом и бактрекинга, я готов.

luetick 10.01.2012 23:45

а скажите, как файл батника выглядит? какое у него название, совпадает с названием проекта?

Винитарх 10.01.2012 23:51

Цитата:

Сообщение от luetick (Сообщение 612528)
а скажите, как файл батника выглядит? какое у него название, совпадает с названием проекта?

Имя батничка capdos. Его содержимое:
Цитата:

"d:\Lesson\Exe\lesson.exe"
pause
Мой проект носит имя Lesson.

luetick 11.01.2012 00:01

нашла. Это pause еще и в самой консоли появляется, после хэловорда.

aag 11.01.2012 00:07

О сравнении списков.
Например, мы любопытствуем самый быстрый путь из А в Б. Из самых быстрых желаем выдернуть самый дешёвый. А из самых быстрых&дешёвых - ну, нехай где меньше всего пересадок...
Выбираем минимальный [Время, Деньги, Пересадки]

Пример из простейших...

Сравнение списков - дюже хрень полезная)))

Винитарх 11.01.2012 00:13

Цитата:

Сообщение от aag (Сообщение 612545)
Это pause еще и в самой консоли появляется, после хэловорда.

Угу. Читайте пункты 7,8 в сообщении №1 этой темы.
Цитата:

Сообщение от aag (Сообщение 612545)
Например, мы любопытствуем самый быстрый путь из А в Б. Из самых быстрых желаем выдернуть самый дешёвый. А из самых быстрых&дешёвых - ну, нехай где меньше всего пересадок...
Выбираем минимальный [Время, Деньги, Пересадки]
Пример из простейших...
Сравнение списков - дюже хрень полезная)))

Да. И не надо термы городить, а потом их ручками по аргументам отдельно сравнивать. +1.


Часовой пояс GMT +4, время: 02:18.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.