Выразителен ли «почти чистый» Пролог?

@false прокомментировал ранее:

Да, вы можете реализовать машину Тьюринга без dif/2. Но вы даже не можете реализовать пересечение или подобные предикаты.

Предположим, мы расширяем чистый Пролог (Horn FOL + CWA + UNA ) с помощью call/N, dif/2 и (=)/3, которые будут использоваться в if_/3, будут ли по-прежнему пробелы в его выразительности, т.е. вещи, которые тривиально определить, скажем, на Схеме, но гораздо сложнее сформулировать в таком расширенном (почти чистом) Прологе?

В частности, позволяет ли такой Пролог манипулировать списками Пролога так же удобно, как Scheme позволяет манипулировать списками Scheme?


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

А как насчет (есть)/2? Вам в значительной степени нужны ошибки инстанцирования, nonvar/1 и Ground/1 для защиты от непреднамеренного использования.

false 23.12.2020 17:04

@false Я думал о Схеме без чисел, строк или символов. Просто символы. Я отредактирую, чтобы уточнить.

MWB 23.12.2020 17:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
682
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

eval(P*Q, H) :- !,
   eval(P, R),
   eval(Q, S),
   reduce(R, S, H).
eval(X, X).

reduce(b(R), S, J) :- !,
   subst(R, 0, S, H),
   eval(H, J).
reduce(R, S, R*S).

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

Вот пример запроса, SUCC и ZERO взяты из здесь:

?- ZERO = b(b(0)), SUCC = b(b(b(1*(2*1*0)))), 
   eval(SUCC*(SUCC*ZERO)*f*a, X).
ZERO = b(b(0)),
SUCC = b(b(b(1*(2*1*0)))),
X = f*(f*a)

В Scheme вы можете тривиально проверить равенство if-then-elseish. Не так в Прологе без dif/2.

false 23.12.2020 17:02

Удачи с dif/2, в SWI-Prolog вы не можете комбинировать его с unify_with_occurs_check/2, см. здесь: stackoverflow.com/q/65532899/502187

user502187 01.01.2021 20:25

Просто символы и списки (деревья).

Вам также нужны логические значения схемы #t и #f, если вы не хотите кодировать все в чистом лямбда-исчислении. Вы также исключаете значения функций, что, к счастью, упрощает этот ответ. Хотя вам придется разрешить частный случай форм верхнего уровня (define name (lambda ...)). (Все остальное, включая расширенные let выражения, может быть дефункционализировано.)

Итак, мое утверждение таково: нет, между этим расплывчатым подмножеством Схемы и чистым Прологом, как вы его определили, нет разрыва в выразительности. Мой аргумент (это не доказательство) конструктивен, он переводит код схемы для пересечения списка из этого ответа в Пролог.

В частности, это:

(define intersect
  (lambda (set1 set2)
    (cond
      ((null? set1)(quote ()))
      ((member? (car set1) set2)
       (cons (car set1)
             (intersect (cdr set1) set2)))
      (else (intersect (cdr set1) set2)))))

становится:

intersect(Set1, Set2, Result) :-
    cond([
        ['null?'(Set1), result([])],
        [cond_1(Set1, Set2), body_1(Set1, Set2)],
        [else, body_2(Set1, Set2)]], Result).

cond_1(Set1, Set2, Result) :-
    car(Set1, Car),
    'member?'(Car, Set2, Result).

body_1(Set1, Set2, Result) :-
    car(Set1, Car),
    cdr(Set1, Cdr),
    intersect(Cdr, Set2, PartialIntersection),
    cons(Car, PartialIntersection, Result).

body_2(Set1, Set2, Result) :-
    cdr(Set1, Cdr),
    intersect(Cdr, Set2, Result).

и это:

(define member?
  (lambda (a lat)
    (cond
      ((null? lat) #f)
      (else (or (equal? (car lat) a) 
                (member? a (cdr lat)))))))

становится:

'member?'(A, Lat, Result) :-
    cond([
        ['null?'(Lat), result('#f')],
        [else, or([or_case_1(Lat, A),
                   or_case_2(Lat, A)])]], Result).

or_case_1(Lat, A, Result) :-
    car(Lat, Car),
    'equal?'(Car, A, Result).

or_case_2(Lat, A, Result) :-
    cdr(Lat, Cdr),
    'member?'(A, Cdr, Result).

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

В этих определениях используются следующие переводы стандартных конструкций Scheme:

'equal?'(X, Y, '#t') :-
    =(X, Y, true).
'equal?'(X, Y, '#f') :-
    =(X, Y, false).

'null?'(Value, Result) :-
    'equal?'(Value, [], Result).

car([Car | _Cdr], Car).

cdr([_Car | Cdr], Cdr).

cons(Car, Cdr, [Car | Cdr]).

or([], '#f').
or([Goal | Goals], Result) :-
    if (Goal,
       Result = '#t',
       or(Goals, Result)).

cond([], _Result) :-
    throw(error(cond_without_else, _)).
cond([[Condition, Body] | OtherCases], Result) :-
    if (Condition,
       call(Body, Result),
       cond(OtherCases, Result)).

Некоторые вспомогательные материалы для получения простого значения из тела случая cond и для случая else:

result(Result, Result).

else('#t').

И это вся внутренне нечистая, внешне чистая поддержка Пролога, которая вам нужна:

if (Goal, True, False) :-
    call(Goal, Truth),
    (   Truth == '#t' -> call(True)
    ;   Truth == '#f' -> call(False)
    ;   throw(error(type_or_instantiation_error(Truth), _)) ).

Я назвал это if/3 вместо if_/3, потому что это не совсем «стандарт» if_/3: он ожидает, что условие будет оцениваться как истинное значение схемы, а не true или false. Не стесняйтесь массировать его до «стандартной» формы. Обновлено: есть несколько «достаточно хороших» способов определить (=)/3, которые будут работать в контексте этого ответа, но чтобы избежать дальнейшего отказа от велосипедов, просто используйте определение из https://stackoverflow.com/a/27358600/4391743.

Тесты:

?- 'member?'(a, [x, y, a, c], Result).
Result = '#t' ;
false.

?- intersect([a, b, c, d], [c, d, e, f], Result).
Result = [c, d] ;
false.

Это (=)/3 не чисто.

false 27.12.2020 18:53

Это достаточно чисто, если предположить, что все значения Схемы зашлифованы. Я хотел добавить это в ответ, я обновлю его. В любом случае, замена моего (=)/3 вашим полным определением из stackoverflow.com/a/27358600/4391743 заставляет программу вести себя так же.

Isabelle Newbie 27.12.2020 18:57

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

false 27.12.2020 23:34

«Это достаточно чисто, если исходить из предположения, что все значения Scheme являются шлифованными». Это не предположение. Если вы переводите процедуру Scheme в предикат Prolog, она должна правильно работать (как и Scheme) с наземными «входами», но может применяться и к неосновным (в противном случае зачем использовать (почти чистый) Prolog?) Фактическое предположение указано в первом абзаце.

MWB 28.12.2020 07:08

«Вам также нужны логические значения схемы». Добавлено, спасибо. Хотя я думаю, что логические значения не важны. Другие Лиспы используют 'T и () для представления #t и #f.

MWB 28.12.2020 08:36

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

Isabelle Newbie 28.12.2020 08:52

Я удалил свой собственный (=)/3 в пользу ссылки на полную реализацию.

Isabelle Newbie 28.12.2020 10:09

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

false 29.12.2020 14:59

+100 за усилия, но я не согласен с вашей интерпретацией вопроса.

MWB 01.01.2021 11:21

Вы могли бы заявить ранее, что не согласны с моей интерпретацией; вы все еще не говорите то, с чем не согласны. В примечании к награде особо упоминалось, что вы примете перевод вашего фрагмента схемы на Пролог. Я не реализовал транслятор, но дал переводы всех соответствующих конструкций Scheme.

Isabelle Newbie 01.01.2021 19:38
Ответ принят как подходящий

Просто symbol/1 и dif/2 являются достаточными расширениями логически чистого Пролога.

Доказательство:

Этот ответ содержит оценщик выражений схемы, evil/2. Он понимает lambda и quote и может быть легко расширен для обработки встроенных процедур списка, таких как list, car, cdr и т. д. Помимо чистого (Горн) Пролога, он использует только symbol/1 и dif/2. Хотя это интерпретатор и будет работать медленно, его существование показывает, что те же самые операции со списками, которые выполняет Scheme, могут быть выполнены в таком почти чистом Прологе. (Я думаю, что symbol/1 тоже не понадобился бы, если бы символы Схемы были переведены в symb(prolog_atom), а не напрямую в prolog_symbol)


Редактировать

Это расширяет evil/2 для обработки if, #t и #f (представленных true и false):

evil(true, _, true).
evil(false, _, false).

evil([if, E1, E2, E3], Env, Val) :-
    evil(E1, Env, false),
    symbols(E2),
    evil(E3, Env, Val).

evil([if, E1, E2, E3], Env, Val) :-
    evil(E1, Env, V),
    dif (V, false),
    symbols(E3),
    evil(E2, Env, Val).

Это расширяет evil/2 до обработки equalp. Он даже мощнее, чем Scheme eq*, поскольку он также будет приравнивать некоторые замыкания:

evil([equalp, E1, E2], Env, true) :-
    evil(E1, Env, V),
    evil(E2, Env, V).

evil([equalp, E1, E2], Env, false) :-
    evil(E1, Env, V1),
    evil(E2, Env, V2),
    dif (V1, V2).

Это оценщик для выражений Scheme, который не включает в себя какую-либо форму cond или проверку на равенство. Учитывая, что проверка на равенство является основной проблемой для реализации пересечения списков, это «доказательство» не показывает того, что вы думаете.

Isabelle Newbie 31.12.2020 11:53

@IsabelleNewbie Проблема с intersection заключалась в отсутствии неравенства. Однако этот Q специально позволяет dif/2. Я думаю, что evil/2 можно тривиально расширить для обработки условных операторов (используя (=)/2 и dif/2).

MWB 31.12.2020 12:11

@IsabelleNewbie добавила if, #t и #f. (Хотя я помню некоторые дискуссии о том, что лямбда-исчисление не нуждается в них) - может быть глючит, т.к. что происходит, когда вы делаете (lambda (#t)..), но это должно быть поправимо, если это так.

MWB 31.12.2020 12:31

«Хотя я помню некоторые дискуссии о том, что лямбда-исчисление не нуждается в них». Они не нужны в том смысле, что вы можете придумать способ кодирования их как лямбда-выражений, точно так же, как вы можете кодировать натуральные числа, списки, а все остальное как лямбды. Но если вы такой редукционист, ваш первоначальный вопрос становится бессмысленным: мы знаем, что вы можете закодировать схему на машине Тьюринга, поэтому неудивительно, что вы можете закодировать ее на Прологе.

Isabelle Newbie 31.12.2020 13:05

В любом случае, здесь все еще не хватает equal?, для чего вам понадобится какой-то способ определения равенства, например, (=)/3.

Isabelle Newbie 31.12.2020 13:08

@IsabelleNewbie «этому по-прежнему не хватает равенства?, для чего вам понадобится какой-то способ определить равенство, например, (=)/3». -- добавил equalp.

MWB 01.01.2021 11:17

@IsabelleNewbie «Но если вы такой редукционист, ваш первоначальный вопрос становится бессмысленным: мы знаем, что вы можете кодировать схему на машине Тьюринга, поэтому неудивительно, что вы можете кодировать ее на Прологе» — я бы предложил вам повторить evil/3 без dif/2, используя только предложения Хорна, тогда (должны давать правильные и только правильные результаты)

MWB 01.01.2021 11:21

@bobcat, почему вы описываете dif/2 как «расширение» логически чистого пролога. Отождествляем ли мы «логически чистый пролог» с «чистым прологом предложения Хорна»?

Jason Hemann 05.03.2021 21:13

Другие вопросы по теме