to post messages and comments.

Вот есть задача составления расписания с ограничениями, это типичная задача для пролога, классы типов в haskell это prolog-like программирование. Вопрос можно ли решить задачу с составлением расписания чисто на уровне типов в haskell, и какие есть ограничения на задачу, которую можно решить?

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

не могу вкурить где тут косяк

:- [ais].

parseParameter(Atom, Term) :- read_term_from_atom(Atom, Term, [ ]).

parseParameters(Atoms, Terms) :- maplist(parseParameter, Atoms, Terms).

matchRules(Action, Result) :- rule(Action, Attributes), permutation(Attributes, Result).

server(Port) :-
http_server(http_dispatch, [ port(Port) ]).

aisReply(Request) :-
catch(http_parameters(Request, [ result(Result, [ list(atom) ] ) ]), _E, fail), !, format('Content-type: text/plain~n~n'), parseParameters(Result, Terms), matchRules(Action, Terms), write(Action).

из консоли все выполняется ок

?- parseParameters(['логин("M1234567890")', 'типОбращения(неисправность)', 'объектОбращения(интернет)'], Terms), matchRules(Action, Terms).
Terms = [логин([77, 49, 50, 51, 52, 53, 54|...]), типОбращения(неисправность), объектОбращения(интернет)],
Action = сбросСессии ;
false.

если же дергать через http то goal unexpectedly failed а если выкинуть &result=логин("M1234567890") то матчицо ок

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

решил проверить tuprolog — реализацию пролога на java. И в итоге я оказался разочарован скоростью его работы. Вот для сравнения за сколько отрабатывают разные пролог-машины на повторяемом 600 раз вычислении палиндрома списка из нескольких десятков элементов с помощью давнешнего рефал-модуля:

tuprolog — 15 секунд
swi prolog — 0.1 секунды
yap — 0.03 секунды

Один плюс у этого тупролога, что у него еще есть экспериментальный пакет для андроида. И хотя там указано, что он для версии >= 2.3.1, но все нормально запускается и на моем 2.2 Froyo.

Еще одна бессонная ночь. Бессмысленная и беспощадная. На этот раз с Прологом. Выяснилось, что он гораздо хуже Лиспа.Он вообще хуже всех походу. ЯП в котором нельзя программировать — говно и ненужен. Не до конца понимаю, зачем его преподают второму курсу математиков. Лучше бы Маткад какой-нибудь. И да, хватит на сегодня альтруизма

Продолжаем играться с прологом и рефалом. На этот раз добавим к нашей реализации рефаловского сопоставления по образцу жадные(greedy) переменные.

Напомню, что в языке Рефал есть такая интересная возможность, как паттерн-матчинг с так сказать "опережающим" поиском. (про Рефал писали, например, в недавнем номере ПФП). Т.о., предикат списка-палиндрома в рефале можно описать так:

Pal {
s.1 e.2 s.1 = <Pal e.2> ;
s.1 = True ;
= True;
e.1 = False ;
}

где e. переменные могут принимать любое значение подсписка (пустой, из одного или более элементов), а s. — один элемент списка.

Мы пытаемся построить с помощью пролога такой DSL, который позволил бы использовать рефаловское сопоставление по образцу (попутно добавив несколько других интересных плюшек :).

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

==
?- re([e(A), e(B)], [1,2,3]).
A = [],
B = [1, 2, 3].

?- re([e*(A), e(B)], [1,2,3]).
A = [1, 2, 3],
B = [].
==

Как видите, во втором примере "жадная" переменная A захватила максимально допустимое паттерном число элементов. Еще пример:

==
?- re([e(A), s(B), e(C)], [1,2,3]).
A = [],
B = s(1),
C = [2, 3].

?- re([e*(A), s(B), e(C)], [1,2,3]).
A = [1, 2],
B = 3,
C = [].
==

Добавим еще один тип переменных — непустые e-переменные. Назовем их "e+" переменные. Пример использования:
==
?- re([e+(A), e(B)], [1,2,3]).
A = [1],
B = [2, 3].

?- re([e*(A), e+(B)], [1,2,3]).
A = [1, 2],
B = [3].
==

И, в заключении, самый интересный, на мой взгляд, пример. Не забываем, что под капотом у нас пролог:
==
?- re([A,B], [1,2,3]).
A = s(1),
B = e([2, 3]).
==

В этом примере мы не указали тип переменных A и B, и пролог подставляет возможные значения типов переменных сам! Подставляет так, чтобы удовлетворить ограничению в две переменные. (замечу, что предлагается только 1 вариант, т.к. в реализации нашего DSL каждое правило оканчивается отсечением).

Вот такой вот получился наколеночный рефал :)

p.s. исходный код этой поделки на pastebin.com

В #1481938 я наврал. allocate/1 и deallocate/0 занимаются выделением активационных записей на отдельном стеке. Там хранятся только локальные переменные, которые понадобятся в коде предиката несколько раз. HEAP также организован в виде стека. HEAP, средствами WAM, очищается только на бэктрейсинге, когда удаляются все изменения сделанные в памяти после последней choice point.

скачал 5й рефал, скомпилял и сравнил скорость вычисления палиндрома :) Рефал считает на порядок быстрее (в 10 с небольшим раз быстрее), чем моя прологовская реализация "рефаловского" сопоставления по образцу из предыдущего поста. Не так и плохо, я доволен :) Все-таки там ядро на си и идет компиляция в байткод.

попытаемся реализовать "рефаловское" сопоставление по образцу с помощью пролога. В рефале есть интересная возможность паттерн-матчинга с т.с. "опережающим" поиском. (про язык Рефал писали в недавнем номере ПФП).

Т.е. например предикат списка-палиндрома в рефале можно описать примерно так (синтаксис некоего условного рефал-языка взят по памяти):

pal( ).
pal(s.X).
pal(s.X e.Y s.X) :- pal(e.Y).

где e. переменные могут принимать любое значение подсписка (пустой, из одного или более элементов), а s. — один элемент списка. Такая интересная возможность, как мне кажется, могла бы быть востребована, например, во всякого рода трансляторах.

Но кроме как в рефале в явном виде такого механизма, как будто, и нет. Попытаемся реализовать такое поведение на прологе:

pref([], [X|Xs], [X|Xs]).
pref([X|Prefix], [X|List], Rest) :- pref(Prefix, List, Rest).

re([X | Pat], [X|Xs]) :- re(Pat, Xs), !.
re([e(X) | Pat], Xs) :- pref(X, Xs, Rest), re(Pat, Rest), !.
re([e(X)], X) :- !.
re([], []) :- !.

И теперь предикат списка-палиндрома на прологе можно записать так:

pal([]) :- !.
pal([X]) :- !.
pal(A) :- re([X, e(Y), X], A), pal(Y).

получился почти рефал :)

а вот хочется мне рефаловского паттерн-матчинга в прологе. посоветуйте какой инструмент лучше использовать? в идеале бы расширение синтаксиса для какого-нибудь swi-prolog'а

Для тех кому интересно одно из интересных применений Agent Oriented парадигмы, Prolog – ted.com . Я не совсем уверен кто это конкретно такой, но мой клиент работает с их отделом в MIT ^_^. Reverse Engineering of Brain. Хотя если честно, в основном пялимся в Excel.

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

Очень хороший пример этого предоставлен в книге Тэйта про дельфина. В том примере, дельфина учили слову NOT ( то есть говоря ему touch not ball, дельфин должен был коснутся чего угодно кроме мячика ).

Кроме того используется для мышей, обезъян и в зоопарках для стандартных животных, таким образом, можно понять когда с животными что то не так – когда они начинают отклонятся от своих виртуальных двойников.

Для закрепления материала, буду писать о своих успехах и неудачах в прологе время от времени тут. Далее, используется SWI-Prolog ( 5.8.3 ). На случай, если я буду использовать термин AOP – это всегда означает Agent Oriented Programming, никаких Аспектов. <br/>
Одной из важных частей Prolog'а является KnowledgeBase. Базу можно фактами и правилами.<br/>
Факт ( Fact ) – это структура, содержащая в себе атомы, и другие факты.<br/>
Правило ( Rule ) — Это разноцидность функтора/эффектора. Если не работали с Декларативными языками, можно считать что это функция.<br/><br/>
Напишем файлик ( "specialists.p"):
person(joe, sap).
person(fred, sap).
person(peter, microsoft).
person(steve, microsoft).

collegues(X, Y) :- person(X, Z), person(Y, Z).

Первые четыре строчки, объявляют факты: Joe работает в SAP, Фрэд работает в САП, Питер и Стив работают в Майкрософте.

Последня строчка – правило. У нас есть два входящих параметра: X, Y. В теле Правила, мы описываем условие: нам нужно чтобы второе поле ( Z ) было одинаковым у обоих персон. Например если бы мы написали person(X, Z), person(Y, A).

Откомпилируем KnowledgeBase:
?- ['specialists.p'].
% specialists.p compiled 0.00 sec, 208 bytes
true.

?- collegues(joe, fred).
true.

?- collegues(joe, steve).
false.

Год назад видел в рассылке haskell-cafe такую задачу: есть два списка, ns :: [Int] и xs :: [T]. Нужно разбить список xs на подсписки длинами из ns. Т.е. takeList [2,1,3] "omgwtf" = ["om", "g", "wtf"]. К этой задаче приводили несколько решений разных уровней навороченности. Потом я линк на все это дело потерял, и вот наконец-то опять нашел. "Новичковское" решение выглядит так:

takeList [] _ = []
takeList _ [] = []
takeList (n : ns) xs = head : takeList ns tail
where (head, tail) = splitAt n xs

А самое продвинутое — вот так:

takeList = evalState . map (State . splitAt)

А на прологе (отсюда: kerneltrap.org ) — оказывается, можно даже вот так (устанавливается зависимость между исходным списком Xs, списком длин Ls и результатом — списком подсписков — Ps):

takeList(Xs,Ls,Ps) :- maplist(length,Ps,Ls), flatten(Ps,Xs).

Млин, я потратил довольно много времени, прежде чем понял, что мои предикаты работают, просто при вычислении надо давать интерпретатору на каждом шагу команду ";" для дизъюнкции, а не точку, он тогда завершает просмотр.