Мне казалось, что я понимаю, как соответствие шаблонов, найденное в Scala, и Haskell отличается от унификации, найденной в Prolog, но мои недопонимания Prolog великолепны. Какие простые проблемы решаются теми, которые не могут быть решены другим? Спасибо вам
Различия между сопоставлением шаблонов и унификацией?
Ответ 1
Простая инструкция: соответствие шаблонов односторонне, унификация является двусторонней. То есть в Prolog правая часть (совпадающая с ней) может включать несвязанные переменные. Например, если у вас есть две несвязанные переменные X
и Y
, это будет работать нормально:
X = Y,
X = 5,
%% Y = 5 now as well
В Erlang (который использует сопоставление образцов с синтаксисом, близким к Prolog), строка X = Y
приведет к ошибке: variable 'Y' is unbound
. Обратите внимание, что X
является несвязанным в порядке: он должен быть сопоставлен с образцом.
Это может быть полезно, если вы хотите иметь дело с частично определенными значениями. Хорошим примером является список различий.
Это также позволяет использовать предикат Prolog в нескольких режимах. Например. в Scala/Haskell/Erlang, если вы хотите 1) найти A ++ B
, 2) решить уравнение A ++ X == B
или 3) решить уравнение X ++ A == B
для данных списков A
и B
, вы необходимо написать 3 отдельные функции; в Prolog все эти задания (и многое другое!) выполняются одним предикатом.
Ответ 2
Я думаю, что полезно формализовать понятия, вместо того, чтобы смотреть на определенный язык. Согласование и унификация - это фундаментальные концепции, которые используются в большем количестве контекстов, чем сопоставление с образцом и пролог.
- Термин s соответствует t, если существует подстановка phi такая, что phi (s) = t
- Член s унифицируется с членом t, если существует такая замена, что phi (s) = phi (t)
Чтобы привести пример, мы проверяем члены s = f (Y, a) и t = f (a, X), где X, Y - переменные, a - постоянная. s не соответствует t, потому что мы не можем универсально количественно определить константу a. Однако существует унификатор для s и t: phi = {X\a, Y\a}
Ответ 3
В Scala не удалось выполнить компиляцию, так как первая ветвь case пытается объявить переменную x
дважды.
(1, 1) match{
case (x, x) => println("equals")
case _ => println("not equals")
}
Если Scala использовать унификацию вместо соответствия шаблону, это будет успешным и напечатать "равно", а
(1, 2) match{
case (x, x) => println("equals")
case _ => println("not equals")
}
будет печатать "не равно". Это происходит из-за сбоя объединения при попытке привязать переменную x
к 1
и 2
.
Ответ 4
В Prolog вы можете добавить [3] к [1,2] следующим образом:
?- append([1,2], [3], Z).
Z = [1, 2, 3].
Оптимальная вещь об объединении состоит в том, что вы можете использовать один и тот же код (внутреннее определение "append" ), но вместо этого найдите второй аргумент, необходимый для получения результата из первого аргумента:
?- append([1,2], Y, [1,2,3]).
Y = [3].
Вместо того, чтобы кодировать, написав "сделайте это, тогда сделайте это", вы закодируете в Prolog, указав то, что знаете. Пролог рассматривает факты, которые вы даете им как уравнения. Унификация позволяет использовать эти уравнения и решать любые переменные, которые вы еще не знаете значения, независимо от того, находятся они справа или слева.
Итак, например, вы можете написать планировщик в Prolog, и вы можете запустить его "вперед", предоставив ему план и предсказать его результаты; или вы можете запустить его "назад", предоставив ему набор результатов и построив план. Вы можете даже запустить его в обоих направлениях сразу (если вы были осторожны в своем кодировании), указав набор целей и набор ограничений для плана, чтобы вы могли сказать "Найдите план для работы, который не включает взяв метро."