Pull to refresh

Comments 62

Странная у вас подсветка синтаксиса. Исправьте.
Не подскажите как? Я уже искал и использую: source — тег с именем lang=«Prolog», работает странновато. А внешних для Пролога не нашел.

% Example comment

predictate_example(Variable) :- predictate_example(1, 'String', Variable).

not_in(X,[]).
not_in(X,[Y|W]) :- X != Y, not_in(X,W).
b(0, []).
b(X, [Z|W]) :- X is Y + 1, b(Y,W), a(Z), not_in(Z,W)!.
first(X,[X|Y]).
subset([], X).
subset([X|Y],[Z|W]) :- X=Z, subset(Y,W).
subset(X,[Y|Z]) :- subset(X, Z).
subset2([X|Y],[Z|W]) :- X=Z, subset(Y,W).
subset_a([]).
subset_a(X) :- integer(N), b(N, Z), subset2(X, Z).

Так? b строит множество из n элементов. Остальное выделяет все подмножества в нем.
Исправив небольшую ошибку +- и убрав лишние, думают суть осталась:
b(0, []).
b(X, [Z|W]) :- X is Y - 1, b(Y, W), a(Z), not(member(Z, W)), !.

subset([], X).
subset([X|Y],[X|W]) :- subset(Y,W).
subset(X,[_|Z]) :- subset(X, Z).

%% ints - not standard predicate, 
%% generates all numbers start from 0
subset_a([]). 
subset_a([NthEl|RestSubset]) :- ints(N), b(N, [NthEl|Rest]), subset(Rest, RestSubset).


Наверняка идея правильная, к сожалению не имею возможности пока проверить. Вы запускали?

Хотя есть гораздо более интересный вопрос (не входил в условие задачи), а возможно сделать это без отсечения?
Ой-ой Y is X -1 (это я ошибся, а ваш вариант с переменной справа от is не является стандартным).
Еще и начальное правило не исправил у вас:
subset([], []).
Не запускал. У меня нет пролога. Я с ним знаком по одной книжке из библиотеки, прочитанной лет десять-пятнадцать назад. Современный пролог для меня потемки.
Современного пролога не существует. Вообще, большая часть технологий, которые нам преподносятся как новые, на самом деле просто хорошо забытое старенькое (применительно к программированию, конечно).
Так данное решение близко к правильному, обладает небольшими неточностями, публикую работающее решение:

ints(0).
ints(X) :- ints(Y), X is Y + 1.

sub_set([], []).
sub_set([X|Y],[X|W]) :- sub_set(Y,W).
sub_set(X,[_|Z]) :- sub_set(X, Z).

 a(1).
 a(2).
 a(3).
% a(X) :- ints(X).

set_a(0, []).
set_a(X, [Z|W]) :- Y is X - 1, Y >= 0, set_a(Y, W), a(Z), not(member(Z, W)), !.

subset_a([]). 
subset_a([NthEl|RestSubset]) :- ints(N), set_a(N, [NthEl|Rest]), sub_set(RestSubset, Rest).


К сожалению у этого решения есть один недостаток, оно никогда не скажет False. То есть перебрав все подмножества конечного множества, система зависнет. Не знаю как от него избавиться.

И приза решение написанное без среды разработки однозначно заслуживает :)
У Вашего решения есть еще один недостаток — оно вносит ограничения, не указанные в условии
> дан некоторый одноместный предикат a/1 (в общем случае множество элементов не ограничено, может быть бесконечно
Про то, что это множество натуральных чисел в условии не сказано. Решение не может быть расширено на любое множество термов.
Предлагаю альтернативное решение, оно более общее. В нем используются следующие свойства Пролога:
1. Как я упоминал в комментарии к предыдущей статье, Пролог не является чистым декларативным языком, поскольку порядок вычислений сильно зависит от порядка предикатов в правиле и от порядка объявления самих правил
2. Порядок выборки фактов из БД зависит от порядка их добавления, т.е. является детерминированным. Таким образом, на множестве объявленных и выводимых фактов неявно определено отношение порядка.

a(b).
a®.
a(d).
a(e).

sub_set([], []).
sub_set([X|Y],[X|W]) :- sub_set(Y,W).
sub_set(X,[_|Z]) :- sub_set(X, Z).

subset_a([]).
subset_a(XS) :- a(L), a®, middle(L, R, Z), sub_set(X, Z), uni([L|X], [R], XS).

middle(X, X, []) :- !.
middle(X, Y, Middle) :- before(X, XB), before(Y, YB), member(X, YB), diff(YB, [X|XB], Middle).

before(X, Y) :- before(X, [], Y).
before(X, E, Y) :- a(XB), not(member(XB, E)), !, fringe(X, XB, E, Y).

fringe(X, X, E, E) :- !.
fringe(X, XB, E, Y) :- before(X, [XB|E], Y).

diff(X, [], X) :- !.
diff([], _, []) :- !.
diff([X|XS], Y, [X|YS]) :- not(member(X, Y)), !, diff(XS, Y, YS).
diff([_|XS], Y, YS) :- diff(XS, Y, YS).

uni(X, [], X) :- !.
uni([], X, X) :- !.
uni([X|XS], Y, [X|YS]) :- not(member(X,Y)), !, uni(XS, Y, YS).
uni([_|XS], Y, YS) :- uni(XS, Y, YS).
Числа не важны в предыдущем решении, замените на буквы или строки, будет работать. Действительно, что важно, чтобы значения не повторялись, так как участвует предикат member/2.

В вашем решении присутствует странный элемент a®? Если убрать его в двух местах, то программа выдает все подмножества из одного элемента.

a('r') без кавычек. В первом случае буква маленькая, во втором — большая
Работает для вашего примера!
Но если взять a(X) :- ints(X), бесконечное множество то элемент 0 все время остается?
Может это специфика, что вы принимали a(X) как набор фактов, а не правил?

X = [];
X = [0];
X = [0, 1];
X = [0, 1, 2];
X = [0, 2];
X = [0, 2, 1, 3];
X = [0, 2, 3];
X = [0, 1, 3];
X = [0, 3];
Да, для бесконечного множества первый элемент всегда будет присутствовать. Решение основано вот на чем: если множество упорядочено, можно взять любое подмножество и определить у него нижнюю и верхнюю границу. Или, наоборот, можно взять два элемента, и определить подмножество, для которых эти элементы будут граничными. Тогда чтобы получить все подмножества, достаточно менять верхнюю границу, пока это возможно, после поменять нижнюю и повторить.
Для бесконечного множества просто никогда не будет найдено предела верхней границы, а значит, никогда не изменится нижняя.
Прошу прощения, не очень внимательно посмотрел Ваш вариант. Ваше решение зацикливается потому, что Вы используете предикат ints(N), который никогда не обернется в ложь, т.е. у Вас нет проверки, есть ли еще необработанные элементы множества. Боюсь, чтобы это исправить, не препарируя все решение, потребуется выбрать сразу все множество, что невозможно, если оно бесконечно.
Да я тоже ломал голову, чуть не сломал. Хотелось вставить какое-то отсечение если один предикат set_a(N, [NthEl|Rest]) не срабатывает, то сразу выйти из всей генерации. Но из-за того, что все время происходит бэктрэкинг, set_a не срабывает сразу после же первого возврата к ints.

В общем так и запишем, конструктивный недостаток решения.
?- subset_a(X).
X = [];
X = [b];
X = [d];
X = [e];
false.
Какой интерпретатор? В моем SWI выдает
1 ?- subset_a(X).
X = [];
X = [b];
X = [b, c];
X = [b, c, d];
X = [b, d];
X = [b, d, c, e];
X = [b, d, e];
X = [b, c, e];
X = [b, e];
X = [c];
X = [c, d];
X = [c, d, e];
X = [c, e];
X = [d];
X = [d, e];
X = [e];
false.
давайте вы следующую статью посвятите сравнению Пролога с Jess или Drools?
Глубочайшее заблуждение!

" — Почему таких проектов мало?
— Потому что программистов владеющих Пролог крайне мало"

Проектов на прологе мало потому что на нем ничего серьезного не напишешь. Приведенные примеры красивы для статьи из серии «этюды для программистов», но на практике никаких задач не решают.

Мне надо работать с сотнями тысяч фактов в режиме реального времени, на таким объемах тухнет swi prolog.
Какие есть идеи?
Вам нужны факты или правила?

Я посоветую связку Пролога и Базы данных. Например XSB есть ODBC. То есть некоторые правила рассматриваются как external и хранятся в базе данных, зато в Прологе видны как обычные предикаты.

+ Вставку можно организовать традиционными методами (не через Пролог).

Может сотни тысяч и может поддержать некоторая Пролог система, но я бы Прологу не доверял большие объемы данных. Факты и правила больше для программистов, а не для пользовательских данных.
Вы, судя по всему, не разрабатывали интеллектуальные системы, где возникают задачи поиска в пространствах, задаваемых тоннами логических условий, или экспертные системы, или интенсиональные базы данных. Заблуждение о том, что Пролог нельзя использовать в реальных задачах возникает из-за того, что понятие «реальной» задачи у всех разное.
Посоветуйте отладчик программ на Прологе.
Когда-то работал с визуальными отладчиками, потом полностью перешел на консольные (удобно пишешь предикат в коде начать trace, а потом выбираешь отпустить или идти дальше).
www.cs.bris.ac.uk/Teaching/Resources/COMS30106/labs/tracer.html

Хотя проще вообще не пользоваться, а тестировать каждый предикат отдельно, если это конечно возможно. Например программа включает 10 предикатов и вы хотите протестировать member. Значит пишите запросы сначала только к member.
Автор, спасибо, что несете Пролог в массы. Уже всерьез подумываю написать про связку Пролога с реляционными базами данных, чтоб унять пыл «практиков»
У меня в запасе, примеры более конкретных и прикладных задач, как парсер XML :) Первые 2 статьи общие слова и примеры маленьких задач, чтобы незнакомым людям Пролог китайской грамотой не казался.
Пролог красив и каждый уважающий себя программист должен на нем попробовать(для общего развития), но пока реально его применять негде. Любая задача в конечном итоге сводится к декларативному программированию. Ну а если смотреть вообще в корень проблемы, то логика первого порядка слишком скудна для реализации сложных задач протяженных во времени.
ЗЫ: Как-то писал на Visual Prolog. То еще извращение)
сори, «декларативному» читай «императивному»
Это не так. Видите ли, всё императивное программирование можно рассматривать как подмножество функционального, которое является декларативным. А выразительность логики первого порядка даст фору почти любому популярному императивному языку программирования. Есть знаменитое изречение Кнута: «Программы предназначены для того, чтобы их читали люди». Программу на Прологе можно именно читать, ее не нужно трассировать в голове, а этим могут похвастаться немногие языки.
Видите ли, всё императивное программирование можно рассматривать как подмножество функционального, которое является декларативным.

Можно несколько подробнее раскрыть эту мысль?
Если просто, концепции императивного программирование, такие как передача управления, ветвление, подпрограммы, мутабельность данных, исключения и т.п. могут быть выражены в рамках функционального программирования с использованием концепции монады (сразу оговорюсь, монадами тут дело не ограничивается). А монада — лишь одна из многих концепций функционального программирования.
Сначала хотел ответить на предыдущее ваше сообщение с возмущением относительно
>функционального, которое является декларативным
а потом посмотрел на это и понял, что смысла переубеждать очередного восторженного хаскеленуба нет смысла.
Прочитайте определение декларативного программирования. Потом функционального. Потом императивного. Включите мозг и подумайте. Если ">функционального, которое является декларативным" не дойдет, попробуйте еще раз.
Рекомендую познакомиться с понятием «перпендикулярные концепции». Например: функциональное процедурное; декларативное императивное. После этого расскажите мне о глубоком декларативном смысле монадического бинда и о глубокой функциональной сути SQL'а.
Вынужден немного почитать вам нотации. Я не буду использовать слишком общий термин «функциональное программирование», поскольку оно бывает весьма разным, приведу в пример только Haskell. Авторы языка были заинтересованы, что же произойдёт, если все функции сделать чистыми, т.е. без побочных эффектов. Монады в нём являются лишь способом эмуляции поведения, которое в рамках чистоты сложно реализовать.

Тем не менее, нельзя считать императивное программирование подмножество функционального. В библиотеке FC++ (для С++) авторы реализовали (помимо карринга, list comprehensions и пр.) монады. Риторический вопрос: стоит ли считать, что функциональное программирование — подмножество императивного?

Декларативность как слово давно является моветоном в кругах программистов, потому что это прилагательное, а не термин.
Я понимаю причину столь критичного отношение к моему высказыванию. Придется более полно раскрыть мысль. Монады — не только способ «эмуляции поведения, которое в рамках чистоты сложно реализовать», это только одно из их применений. Но дело не в самих монадах. Функциональное программирование основано на лямбда-исчислении и комбинаторной логике. Лямбда-исчисления является простейшим полным по Тьюрингу языком программирования. Более того, большая часть языков программирования (все со статической типизацией) могут быть описаны в терминах лямбда-исчисления, и это известно с 1965г., статьи П.Ландина «Соответствие между языком Algol 60 и лямбда-исчислением». Реализовать отдельные концепции функционального программирования можно на императивном языке, что, собственно, и сделано в FC++, но все концепции императивного программирования могут быть выражены в рамках функциональной парадигмы.
Декларативность — существительное, термин с вполне конкретным значением и глубоким смыслом. Не прилагательное.
Монады — не только способ «эмуляции поведения, которое в рамках чистоты сложно реализовать», это только одно из их применений
О, ну конечно же, это же ещё моноиды в категории эндофункторов. Будьте прагматиком, монады это всего лишь абстракция. Не лучше и не хуже мутабильных переменных, исключений и прочего.

Функциональное программирование основано на лямбда-исчислении и комбинаторной логике.
Подробнее, пожалуйста. Я думал, что оно основано на куда более серьёзной теории, вроде теории типов, formal methods и пр., а не на частном случае их применения. Более того, лямбда-исчислений как таковых далеко не одно и не два. Даже порядков редукции на них пруд пруди (inner-most, outer-most, outer-most graph etc.)

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

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

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

термин с вполне конкретным значением и глубоким смыслом
Так любят говорить филологи. Они часто утверждают, что X имеет глубокий смысл, но никогда не осмеливаются его назвать. Попробуйте ещё.
монады это всего лишь абстракция
А кто спорит? Все, с чем мы имеем дело в программирование выше машинных кодов — абстракция.
любой Тьюринг-полный язык можно подвергнуть трансляции в Тьюринг-полное лямбда-исчисление
Вот Вы и дали определение слова «простейший». В лямбда-исчислении всегда можно найти простейшую форму определения функции. Преобразование де Брейна не дает более простой формы выражения, оно служит только для преобразования лямбда-терма в терм комбинаторной логики.
Функциональное программирование использует более широкий класс теорий. Но в основе лежит лямбда-исчисление и КЛ.
В целом, я готов признать Вашу правоту относительно исходного тезиса об ортогональности декларативной и процедурной парадигм. Но хотелось бы кое-что прояснить. Что за чудеса с типизацией и комбинатором неподвижной точки? И про множество лямбд было бы очень интересно узнать.
Декларативный — [по определению] носящий свойства декларации, то есть определяющий. Декларативное программирование (здесь я не претендую на полноту и безупречность определения) подразумевает описание того, что нужно вычислить, а не как это сделать. В рамках функционального программирования описываются функции, именно описываются, декларативно, т.е. указывается, что такое эта функция, а не как с ее помощью вычислить конкретное значение за конечное число шагов.
выше машинных кодов
Это тоже абстракция :)

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

Что за чудеса с типизацией и комбинатором неподвижной точки?
Ну проблема типизации Y-комбинатора же традиционная, и обычно попросту добавляют fix: forall a. (a -> a) -> a как дополнительный примитив, наряду с лямбда-абстракцией и аппликацией.

подразумевает описание того, что нужно вычислить, а не как это сделать
Я сейчас поясню, почему этим термином нельзя пользоваться. Возьмем Хаскелл. Да, понятно, что ADT только определяет тип, но ничего не говорит о том, как его хранить в памяти и т.п., компилятор должен «придумать» это сам. Однако, он не способен решить какую-нибудь задачу о переправе (капуста, коза и волк, ну вы помните) по одному только определению, придётся написать решение с помощью какой-нибудь монады List самому.
Возьмем С++. Он требует точно описывать, что где хранится. Но он способен сам оптимизировать возвращаемые значения функций (оптимизация RVO), и сам распределяет переменные по регистрам.
Декларативность это не имманентное свойство, это некоторое значение. Оно варьируется в разных языках, и везде отлично от нуля.

Хорошо, что мы сохраняем конструктивный стиль беседы. Я хотел бы в рамках оффтопа привести вот эту ссылку plakhov.livejournal.com/170496.html.
Декларативность не определяет семантику языка. Конечно, решение логических задач типа капусты, козы и волка, на Хаскеле не столь очевидна, как, скажем, на Прологе, но это потому что семантика языка другая. Тем не менее, Хаскель, простите за излишнюю категоричность, можно в некотором роде сравнить с математической нотацией, которая декларативна по определению. На Хаскеле Вы описываете предмет задачи в терминах функций, но не указываете напрямую способ ее решения. В C++ и прочих императивах Вы непосредственно говорите: «чтобы получить результат — сделайте это, потом вот это и т.д.», т.е. описываете не предмет задачи, а конкретно вычислительный процесс. Также на SQL сложновато решить логическую задачу, но этот язык имеет декларативную природу.
Комбинатор неподвижной точки, безусловно, имеет важное практическое значение и может быть определен как примитив, но он также выражается в терминах лямбда-исчисления. Напомню Y = \f.(\x.f(xx))(\x.f(xx))
найти простейшую форму определения функции
Алгоритмическая энтропия тут не при чем (вообще она важна, но это тема для отдельной дискуссии). Имеется ввиду, что в рамках лямбда-исчисления множество вычислимых функций может быть разбито на классы эквивалентности, в каждом из которых существует функция с простейшей формой.
но это потому что семантика языка другая
Здесь следовало согласиться или опровергнуть тезис, что декларативность это неправильное понятие, а не приводить абсурдные аргументы против неизвестного тезиса.

математической нотацией, которая декларативна по определению
Определение математической нотации в студию.

На Хаскеле Вы описываете предмет задачи в терминах функций
На Хаскелле вы описываете предмет задачи на весьма обширном языке, стандарт которого содержится на 200+ страницах, который даже после обстоятельного desugaring превращается в язык с 6 элементами (лямбда-абстракция, аппликация, конструкторы типов, сравнение с образцом, let и ещё что-то, я запамятовал) и десятком правил. Функции действительно встречаются какой-то частью в этом разнообразии.
но не указываете напрямую способ ее решения
Ну это совсем уже смешно. Вы считаете, что нормальный порядок редукции позволяет утверждать, что Haskell не выполяет указанные действия по порядку вообще?
filter (\x. x % 2 == 0) [1..]
«Чтобы получить результат, построй бесконечный список натуральных чисел, затем отфильтруй все нечётные числа. Действия исполняй лениво.»
Ошибка в ваших рассуждениях заключается в том, что мыслить о формальном языке в терминах натурального вообще бессмысленно. Я могу придумать и императивное чтение, и декларативное чтение, и вообще состоящее из одних деепричастий. Это глупо.

Напомню Y = \f.(\x.f(xx))(\x.f(xx))
Как только вы расставите здесь типы (особенно интересует тип x), а ещё лучше — сможете запустить эту функцию в Haskell, тогда мы сможем продолжить беседу на эту тему.

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

простейшей формой
Неформально.
Не знаю как Вы, а я глядя на разложение функции (скажем, sin) по формуле Тейлора, вижу «функция sin(x) может быть представлена в виде ...», а не указание «чтобы вычислить sin(x), нужно просуммировать ...». Но даже с Вашей формулировкой получается декларация
Чтобы получить результат, построй бесконечный список натуральных чисел, затем отфильтруй все нечётные числа. Действия исполняй лениво.
Вы определили результат через другие понятия, а не выстроили порядок вычислений.
Да что вы? А в Си или для машины Тьюринга этого сделать нельзя?
А по какой, интересно, операции? В соответствии с какой теоремой?
простейшей формой
читайте «нормальной» формой
Как только вы расставите здесь типы (особенно интересует тип x), а ещё лучше — сможете запустить эту функцию в Haskell
А причем здесь вообще типы и Хаскель? Лямбда-исчисление изоморфно комбинаторной логике. Y-комбинатор не является чем-то особенным и таинственным, хотя для повышения производительности его можно реализовать как примитив.
Декларативность — правильное понятие. Причисляя язык к классу декларативных, Вы во многом определяете то, как писать на нем программы. Можно и на Прологе писать в императивном стиле, это будет работать, но такие программы получаются очень неуклюжими и почти нечитаемыми. Ваш аргумент про ADT и «коза, капуста, волк», простите, просто смешон. Декларативная природа языка не может служить определением класса задач, к которому этот язык применим. Пролог — язык декларативной природы, но заложенные в него принципы делают его легко применимым к решению логических задач. Компилятор пролога ничего не вычислит, пока Вы не предоставите ему описание того, с чем он должен работать. Хаскель — функциональный язык, область применения и базовые принципы у него другие. Его компилятор также сможет что-либо выполнить только когда как Вы дадите ему определение того, с чем он имеет дело. Описали только алгебраический тип — требуйте результатов в рамках описания этого типа.
Единственное, я полностью согласен, что декларативность присуща любому языку в некоторой степени, также как императивность. Язык декларативен, если императивная составляющая в нем мала по сравнению с декларативной.
Я могу придумать и императивное чтение, и декларативное чтение, и вообще состоящее из одних деепричастий
Математика — это язык, причем формальный. А любой язык — средство выражения мыслей. Вы, конечно, можете sin(a) = CB/AB прочитать как «чтобы вычислить синус, поделить противолежащий катет на гипотенузу», но это не изменить того, что данное выражение суть определение
Вы определили результат через другие понятия, а не выстроили порядок вычислений.
Вот поэтому я и говорю, что мыслить словесно о формальном языке глупо. Это было конструктивное тому доказательство, если не вполне было ясно из контекста.

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

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

Математика — это язык, причем формальный.
Математика это наука. То, что основной метод формального мышления, — языки, а точнее formal systems, утверждать процитированное не позволяет.

Остальное комментировать бессмысленно, поскольку контраргументы вы не прокомментировали, из чего я делаю вывод, что они до вас попросту не дошли. Не возьмусь сказать, на каком этапе восприятия это произошло, но перечитать и попытаться их оспорить рекомендую.
Это было конструктивное тому доказательство
Доказательством это даже не пахнет. То, что Вы написали, есть декларация некоторого понятия «результат», который Вы определили через другие понятия. Это не императив, не указание. Всего лишь определение.
Я спросил про чудеса комбинатора неподвижной точки в контексте упрощения выражения "Даже после банального преобразования де Брейна получается более «простой» язык". В лекции по теории функционального программирования не нуждаюсь, спасибо.

мыслить словесно о формальном языке глупо
Мыслить формально о формальном еще глупее

А, то есть декларативность можно определить только со слов автора
Декларативность — свойство языка. Когда определен синтаксис и семантика языка, наличие или отсутствие этого свойства становится очевидно. Как Вы дошли до такой интерпретации моих высказываний для меня является загадкой.
Математика — это язык, причем формальный.
Это не мои слова. Это сказал Джозайя Гиббс, и после него говорили многие выдающиеся математики и ученые других областей, включая Гильберта и Фейнмана.
Достойных контраргументов я, увы, не услышал. Похоже на то, что Вы видите только вычислительный аспект. Мои аргументы также стреляют в холостую. Поэтому, думаю, нам стоит прекратить дискуссию ввиду ее неконструктивности.
«Декларативность» — неправильный термин (согласен прилагательное), употреблением которого большинство программистов выдают желаемое за действительное. Например, 1 + 2 * 3 — декларативная запись для подсчета на калькуляторе.
Декларативность связана с языком, которым изъясняются люди при постановке задачи. Поэтому для большинства людей все-таки самым декларативным языком будет естественный язык. Программисты пытаются придумать некоторые абстракции, чтобы для пользователя системы язык выглядел наиболее естественным.
Если говорить про Пролог, к сожалению про все языки однозначно говорить не могу, имеет некоторые преимущества:
1. Имеет возможность создавать Domain Specific Language.
2. Создан на основе языка предикатов для автоматического доказательства теорем, то есть является описательным языком теорем. Математический язык сформировался давно и хорошо подходит для задач, теорем, загадок и тп.
Но есть и недостатки:
1. Функциональная составляющая очень важна в математике и в программировании, но полностью отсутствует в Прологе, так как в мат. логике функции не играют значительной роли, а рассматриваются на равне с другими зависимостями (не только функциональными).
2. В Прологе не реализована теория с равенством, из-за этого 1 + 4 <> 5.
3. В Прологе отсутствует декларативное отрицание

Если говорить про С, то это вполне декларативное описание инструкций для выполнения, только понятие цикла, на самом деле, в повседневной жизни гораздо реже встречается, на мой взгляд, нежели чем обычные блок-схемы. Хотя конечно существует однозначное преобразование.
Императивный означает «требующий абсолютного подчинения». Команда на калькуляторе 1 + 2 * 3 — императивна, лингвистически это означает «вычислить <выражение>». Указание. А вот если записать f = 1 + 2 * 3, где равенство используется в математическом смысле, а не в смысле присваивания, получится декларативная запись, поскольку определяется не порядок вычислений, а природа объекта «f». Лингвистически «f — это <выражение>». Определение (декларация). Поэтому блок-схема определяет императивное решение задачи, а запись алгоритма в математической нотации или на языке логики первого порядка — декларативное.
Декларативность связана с языком, которым изъясняются люди при постановке задачи.
Здесь зарыта очередная ошибка, состоящая в том, что устное условие задачи не является полным, и не определяет задачу как таковую. Декларативность — не мера наличия искусственного интеллекта.

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

Имеет возможность создавать Domain Specific Language.
Почти любой язык имеет эту возможность. Даже если язык способен только лишь определять функции, определённый набор функций (библиотека) реализует своеобразный DSEL. Кроме того, прошу не путать DSL и DSEL, потому что DSL можно реализовать вообще не любом Тьюринг-полногом языке.

является описательным языком теорем
Нет, не является.

Стоит отметить, что сообщество небольшое, но очень лояльное: практически все известные языки нашли свое отражение в современных языках (Lisp, ML -> F#, Scala; Smalltalk -> Java, Scala (агенты), скриптовые -> Ruby), в отличие от Пролог.

Постойте, а как же Erlang?
Здесь как вы видите далеко не все языки, да и Erlang можно считать относительно новым языком. Мысль в том, что из всех старых языков, основные идеи или избранное, перетянули в недавно созданные. Я думаю многое из Erlang присутствует в той же Scala.

С Прологом ситуация другая все, что появляется это 35-я модификация Пролога, написанная чисто на Java, причем .NET до сих пор не выпустил ничего официального. Между прочим LLVM по структуре очень похоже на Пролог не изменяемые объекты, переходы по графу, хвостовая рекурсия, отсутствие циклов… Может быть идеи Пролога витают в воздухе ;)
>Erlang можно считать относительно новым языком
since 1986 — на молодой не тянет.
>не изменяемые объекты, переходы по графу, хвостовая рекурсия, отсутствие циклов
Вы описали 99% всех функциональных языков.
Не увидел в вашей контраргументации конструктивного объяснения, почему ваше ошибочное утверждение должно остаться неизменным, простите.
Mercury? Вроде бы не такой протухший, как Prolog.
Вы как с плеча «протухший», мне, например, Mercury не совсем понравился.
Вроде кажется, такая ерунда: большинство предикатов в Прологе похоже на функции есть In и Out, в Меркури можно заменить одной конструкцией и структура является понятной. А вот так посмотришь-посмотришь, а может и ничего плохого в этом InList и OutList (пример предикат filter), зато универсально — эстетика.

Пролог — хорош, я думаю он сравним с Lisp, если вы его «протухшим» назвали, думаю вас бы много людей обвинило к не уважении к истокам и предкам. Стоит признать, что программирование до 90-х принесло столько хороших идей, что мы до сих пор не можем их внедрить в нашу «современную среду».
«Просто» Lisp (кстати, какой из?) давным-давно протух. Если бы вы упомянули CL или Racket, было бы о чём говорить.
Новые идеи из 90х? Вы о чём?
Идеи до 90-х до сих пор не в полной мере развиты. Это касается всего: мультипоточного, мультипроцессорного программирования, способов оценки сложности ПО, способов управления командой, чистота вычислений и т.п.
Что-то вы как-то плаваете. Подробнее про якобы «не развитые» идеи.
Хорошо, оценка ПО методом функциональных точек, COCOMO I, COCOMO II до 90-х? Лучше ничего не придумано, а ГОСТ вообще не оправдано забыт. Многие вещи морально устарели, а многие живы.

До 90-х существовали специальные ЛИСП-машины, где они сейчас нету? А представьте какой был бы плюс от построения таких архитектур сейчас и от чистоты вычислений, когда даже в домашнем компьютере 4 ядра, а в промышленных по 128-ядер, а большинство мощностей тупо простаивает, потому что на Java модно программировать. Сейчас появляется Scala, которая пытается решить эту проблему. Но стоит придумывать B, если есть A, для того, чтобы придумать затем C, которое будет ориентироваться на то, что уже было в A.

Я не думаю, что этот спор имеет место, потому как вполне очевидно, что после 90-х программирование переместилось из научной сферы, в сферу бизнеса, которыми руководят абсолютно другие принципы.
Лисп-машин нет по многим причинам. Если собрать аргументацию буквально в нескольких словах, то это будет «не могло работать». Зато есть проект Reduceron, который не так сильно попахивает распилом государственных средств.
UFO just landed and posted this here
Лучше бы задачку решили, а не обзывались.
>оценка ПО методом функциональных точек, COCOMO I, COCOMO II
Нахер это надо?
>До 90-х существовали специальные ЛИСП-машины, где они сейчас нету
Нахер они нужны, если generic железо тупо быстрее? Если очень хочется, вон есть ПЛИСки и открытые ядра к ним. Вроде даже что-то готовое было.
>большинство мощностей тупо простаивает
Што? В каком месте они простаивают? И при чём тут Java? И тем более Scala, которая должна решить какую-то проблему (производительности? Жабы? На JVM? Откуда у вас такая трава?).
>вполне очевидно, что после 90-х программирование переместилось из научной сферы
Мне вот вполне очевидно, что просто вы закостенели мозгом (хоть и в очень раннем возрасте) и ленитесь узнавать что-то новое и следить за происходящим, предпочитая оставаться в плену иллюзорного светлого прошлого. Если бы это было не так, вы бы видели тонны публикаций, вращающихся вокруг систем типов (о которых в 90х даже речи не было) и решений разнообразных проблем мультипроцессорности (которые возникли после 90х, когда производительность наращивалась тупым увеличением частоты) и распределённости. Начиная от пресловутого хаскеля с Racket'ом и заканчивая Agda/ATS с их dependent types.
TLDR: если что-то «забыто», это всего лишь значит, что это никому не нужная херня.
Sign up to leave a comment.

Articles