Как стать автором
Обновить
6
@go-prologread⁠-⁠only

Пользователь

Отправить сообщение
В целом это ,, иной,, способ декомпозиции задач. ограничения, эвристики доступны как и везде. Доступна отладка есть профилиррвщик, да и отладочные печати, логирование реализовать нет проблем…
Не ясно как ваш интерфейс (GUI на Qt/C++), взаимодействует с длл, вот тут:
tashQuestion(Id):-
...
dialog_ynw(Prisnak,Ans),

Этот предикат dialog_ynw() показывает диалог вопроса?, получается в «логическую» часть «зашиты» элементы интерфейса пользователя, странно…, так можно было все и реализовывать на Visual Prolog, графические возможности там достаточные.
Предлагаю записать в виде лямбды(это лисп):
> set 'fct (lambda (n f) (if (zerop n) 1 (* n (funcall f (- n 1) f))))

И вызывать вот так
> funcall fct 100 fct

У вас:


удобный синтаксис
располагающий писать в декларативном стиле и использовать константы.

А в чем же удобство, какие преимущества дает декларативная запись? Не императивны ли сами алгоритмы?

Ну давайте доводить псевдо-Питон до конца,
как там выглядят sort, split?

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

А еще это выражение ничем не отличается от сугубо императивного алгоритма:

Спасибо, это я и пробую описать, мое описание можно дополнить и будет рабочая программа:


split([])->{[],[]};
split([A])->{[A],[]};
split([A,B|T])->{L,R}=split(T),{[A|L],[B|R]}.

Ну и merg:
merg([],[])->[];
merg(X,[])->X;
merg([],X)->X;
merg([A|T],[B|T1]) when A<B->[A|merg(T,[B|T1])];
merg([A|T],[B|T1])-> [B|merg([A|T],T1)].

Сколько придется думать, чтобы реализовать "алгоритм" слияния на императивном языке?
Разве так не проще?

По принципу слияний видно, что деление входного списка происходит пополам, что приведет к рекурсивным вызовам глубины log(n) вне зависимости от данных,
а для быстрой сортировки нужно учитывать, что "неудачный" пивот или отсортированный входной массив заставят ее углубляться n раз.


В общем эти тру слияния можно представить похожим декларативным выражением на Эрланге:


msort([])->[];
msort(X)->{L,R}=split(X), merg(msort(L),msort(R)).

Если это важно то вот, привожу из Википедии:


Время работы алгоритма порядка O(n log n) при отсутствии деградации на неудачных случаях, которая является больным местом быстрой сортировки (тоже алгоритм порядка O(n log n), но только для среднего случая). Расход памяти выше, чем для быстрой сортировки, при намного более благоприятном паттерне выделения памяти — возможно выделение одного региона памяти с самого начала и отсутствие выделения при дальнейшем исполнении.

У нас понятие "алгоритма" может быть независимо от исполнителя, механически можно решать эту задачу, карандашом. Как, там было, "имплементации" присуща память и ее расход, не зря у машины Тьюринга бесконечная лента.

  1. К решателям можно относить вот такие


    clp(fd) is one of several constraint solvers available in SWI-Prolog. The others are clp(b), clp(qr) and CHR. clp(b) handles booleans. clp(qr) handles rationals and reals. CHR approaches constraint programming differently, using rewrite rules.

  2. А управление выводом доступно, это разная формулировка задачи...


почему все понятно с SQL
А с ним "все понятно"? Или вы просто никогда не сталкивались со сложными его случаями?

Для "сложных случаев" стандарт SQL постоянно расширяют… И не решив сложный запрос переписывать на for в for-е, никто не берется.


Получилось основное отличие императивной мысли от декларативной в "реорганизует" в возможности делать swap(). Тут была статья о реализации сортировки слияниями на лентах, от Фон Неймана, там при отсутствие возможности изменять значения на ленте, переписывали всегда все значения на промежуточные ленты.

Принцип описанный тут целиком отображен в программе на Эрланге — она и была быстрой сортировкой, в которой основа разделяй и рекурсивно сортируй ))

Очевидно у меня травма )) детства, но я читал в этой книге (Мейер, Бертран; Бодуен, Клод Методы программирования В 2 томах 1982г) вот такое:

Это тот признак удобнее, понятнее, нам не нужно доказывать таблицу умножения, теорему Пифагора, они и так понятны, они истинны. Какие расчеты там делал Пифагор, мы не интересуемся, также как и Хоар предложил "делить на меньшие и большие", вот основная идея, в рекурсивности и разделении, если делить большую задачу на мелкие, получаем в среднем сложность логарифма — это основной принцип этого быстрого (так сказать) алгоритма.


Другой алгоритм сопоставимый с быстрой, это алгоритм, звучит вот так:
Не делить список на меньшие и большие, а делить РОВНО пополам, а потом merge сливать отсортированные две части.
Это тоже алгоритм сортировки, и они очень похожи между собой. Но сложность последнего точно ровна log(n). И я только что не излагал последовательность сортировки слияниями))
Так какой способ представления, более доступен, понятен, и в каких областях? почему все понятно с SQL, HTML? а с алгоритмом в программе не так? Не про производительность, вычислительную сложность языка SQL, интересуются, людей привлекает абстракция, она заменяет собой большое количество деталей, о которых разработчику знать не нужно при решении задач...

Хочу уточнить свой интерес, мне хотелось понять, а как именно у нас сохранен "в голове" тот алгоритм, или описание самой "быстрой сортировки". Мне интересно узнать, а как мы себе помним, что такое алгоритм.
Это последовательность императивность: 1,2,3,4:


  1. Выберите пивот.
  2. Поместите все, что меньше пивота, до пивота, а все, что больше пивота — после пивота.
  3. Повторите на участке до пивота
  4. Повторите на участке после пивота

Или мысль статична, декларативна:
Если у входного списка есть пивот и хвост [H|T], то
отсортированы он будет если ->
(отсортированы все элементы из Т меньшие пивота H) плюс сам пивот
плюс (отсортированы все большие пивота)
qsort()++[H]++qsort()
Ну, И Пустой [] список всегда отсортирован.


Это как вопрос, о сути субъективности, какой именно способ используем мы (мы как люди, наш мозг) для хранения этого алгоритма быстрой сортировки? )

Это меня и интересует, много нюансов этого «алгоритма» упускаем, приводя его, а ведь алгоритм «должен быть» детерминирован. Когда же его можно назвать «быстрой сортировкой», если даже действия приведены не все, где операция swap().
Тут wiki.haskell.org/Introduction#Quicksort_in_Haskell — пишут о выражении быстрой сортировки, и это она же.
Для декларативного выражения, стоит вводить другой термин «схема», «принцип», а алгоритм это строгость и однозначность, вы ее не показали указав четыре шага.
Спасибо, и вам за внимание )
Точно, можно сказать, что декларативная программа, выражает не алгоритм, а некий «принцип» быстрой сортировки, а детали выполнения зависят от решателя.
Каждый генератор сделает один список, который поступит на следующий уровень вызова, и конкатенация должна быть оптимизирована, это не просто новый список, это хотя бы второй список не обработан, а превращен в хвост…
Тогда, следовало бы писать:
разместите элементы списка так, чтобы пивот оказался на том месте в массиве, что бы все меньшие были слева, а большие справа.

Или, еще точнее:
нужно обменивать между собой элементы справа и слева, до тех пор, пока два индекса справа и слева не встретятся…

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность