Разница между логическим программированием и функциональным программированием

Я читал много статей, пытаясь понять разницу между функциональным и логическим программированием, но единственный вывод, который я смог сделать до сих пор, заключается в том, что логическое программирование определяет программы посредством математических выражений. Но такая вещь не связана с логическим программированием.

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

Ответ 1

Я бы не сказал, что логическое программирование определяет программы через математические выражения; это больше похоже на функциональное программирование. Логическое программирование использует логические выражения (ну, в конечном итоге логика - математика).

По моему мнению, основное различие между функциональным и логическим программированием - это "строительные блоки": функциональное программирование использует функции, тогда как логическое программирование использует предикаты. Предикат не является функцией; он не имеет возвращаемого значения. В зависимости от значения его аргументов оно может быть истинным или ложным; если некоторые значения undefined, он попытается найти значения, которые сделают предикат истинным.

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

Когда вы пишете предикат пролога, вы определяете предложение рога: foo :- bar1, bar2, bar3. означает, что foo истинно, если bar1, bar2 и bar3 истинны. обратите внимание, что я не говорил, если и только если; вы можете иметь несколько предложений для одного предиката:

foo:-
   bar1.
foo:-
  bar2.

означает, что foo истинно, если bar1 истинно или если bar2 истинно

Некоторые говорят, что логическое программирование является супермножеством функционального программирования, поскольку каждая функция может быть выражена как предикат:

foo(x,y) -> x+y.

может быть записано как

foo(X, Y, ReturnValue):-
   ReturnValue is X+Y.

но я думаю, что такие утверждения немного вводят в заблуждение

Другое различие между логикой и функциональностью - это откат. В функциональном программировании, когда вы входите в тело функции, вы не можете потерпеть неудачу и перейти к следующему определению. Например, вы можете написать

abs(x) -> 
   if x>0 x else -x

или даже использовать защитные устройства:

abs(x) x>0 -> x;
abs(x) x=<0 -> -x.

но вы не можете писать

abs(x) ->
   x>0,
   x;
abs(x) ->
   -x.

с другой стороны, в Prolog вы можете написать

abs(X, R):-
   X>0,
   R is X.
abs(X, R):-
   R is -X.

если вы назовёте abs(-3, R), Prolog попытается выполнить первое предложение и завершится неудачно, когда выполнение достигнет точки -3 > 0, но вы не получите ошибку; Пролог попробует второе предложение и вернет R = 3.

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

В целом, хотя обе парадигмы считаются декларативными, они совершенно разные; настолько разные, что их сравнивать - это сравнение функциональных и императивных стилей. Я бы предложил попробовать немного логического программирования; это должно быть ошеломляющим опытом. Однако вы должны попытаться понять философию, а не просто писать программы; Prolog позволяет писать в функциональном или даже императивном стиле (с чудовищными результатами).

Ответ 2

В двух словах:

В функциональном программировании ваша программа представляет собой набор определений функций. Возвращаемое значение для каждой функции оценивается как математическое выражение, возможно, используя переданные аргументы и другие определенные функции. Например, вы можете определить функцию factorial, которая возвращает факториал заданного числа:

factorial 0 = 1                       // a factorial of 0 is 1
factorial n = n * factorial (n - 1)   // a factorial of n is n times factorial of n - 1 

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

factorial(0, 1).               // it is true that a factorial of 0 is 1
factorial(X, Y) :-             // it is true that a factorial of X is Y, when all following are true:
    X1 is X - 1,                   // there is a X1, equal to X - 1,
    factorial(X1, Z),              // and it is true that factorial of X1 is Z, 
    Y is Z * X.                    // and Y is Z * X

Оба стиля позволяют использовать математические выражения в программах.

Ответ 3

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

Но вы хотите знать различия.

Итак, я возьму Haskell с одной стороны и Prolog с ограничениями на другой. Практически все текущие системы Prolog предлагают какие-то ограничения, такие как B, Ciao, ECLiPSe, GNU, IF, SICStus, SWI, YAP, XSB. Для аргумента я использую очень простое ограничение dif/2, означающее неравенство, которое присутствовало даже в самой первой реализации Prolog, поэтому я не буду использовать ничего более продвинутого, чем это.

Какое функциональное программирование отсутствует

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

> let v = iterate (tail) [1..3] 
> v
[[1,2,3],[2,3],[3],[],*** Exception: Prelude.tail: empty list

После 4-го элемента значение undefined. Тем не менее, вы можете безопасно использовать первые 4 элемента:

> take 4 v
[[1,2,3],[2,3],[3],[]]

Обратите внимание, что синтаксис в функциональных программах умно ограничен, чтобы избежать останова переменной undefined.

В логическом программировании переменной не нужно ссылаться на конкретное значение. Итак, если нам нужен список из 3 элементов, мы можем сказать:

?- length(Xs,3).
Xs = [_G323, _G326, _G329].

В этом ответе элементы списка являются переменными. Все возможные экземпляры этих переменных являются допустимыми решениями. Как Xs = [1,2,3]. Теперь скажем, что первый элемент должен отличаться от остальных элементов:

?- length(Xs,3), Xs = [X|Ys], maplist(dif(X), Ys).
Xs = [X, _G639, _G642],
Ys = [_G639, _G642],
dif(X, _G642),
dif(X, _G639).

В дальнейшем мы можем потребовать, чтобы элементы в Xs были равны. Прежде чем я напишу, я попробую сделать это в одиночку:

?- maplist(=(_),Xs).
Xs = [] ;
Xs = [_G231] ;
Xs = [_G231, _G231] ;
Xs = [_G231, _G231, _G231]  ;
Xs = [_G231, _G231, _G231, _G231] .

Посмотрите, что ответы содержат всегда одну и ту же переменную? Теперь я могу комбинировать оба запроса:

?- length(Xs,3), Xs = [X|Ys], maplist(dif(X), Ys), maplist(=(_),Xs).
false.

Итак, мы показали, что нет 3 списка элементов, где первый элемент отличается от других элементов, и все элементы равны.

Эта общность позволила разработать несколько языков ограничений, которые предлагаются в виде библиотек для систем Prolog, наиболее видными являются CLPFD и CHR.

Нет прямого способа получить аналогичную функциональность в функциональном программировании. Вы можете эмулировать вещи, но эмуляция не совсем то же самое.

Какое логическое программирование отсутствует

Но есть много вещей, которые не хватает в логическом программировании, что делает функциональное программирование настолько интересным. В частности:

Программирование более высокого порядка: функциональное программирование имеет здесь очень давнюю традицию и разработало богатый набор идиом. Для Prolog первые предложения относятся к началу 1980-х годов, но все еще не очень распространены. По крайней мере, в ISO Prolog теперь есть гомолог, который называется call/2, call/3 ....

Lambdas: Опять же, возможно расширить логическое программирование в этом направлении, наиболее заметной системой является Lambda Prolog. Совсем недавно lambdas были разработаны также для ISO Prolog.

Типовые системы: Были попытки, такие как Меркурий, но это не так много. И нет системы с функциональностью, сопоставимой с типами классов.

Purity: Haskell полностью чист, функция Integer → Integer - это функция. Никакой мелкой печати не скрывается. И все же вы можете выполнять побочные эффекты. Сопоставимые подходы очень медленно развиваются.

Существует много областей, где функциональное и логическое программирование более или менее перекрываются. Например, откат, ленивость и список, ленивая оценка и freeze/2, when/2, block. DCG и монады. Я оставлю обсуждение этих проблем другим...

Ответ 4

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

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

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

В функциональном программировании мы можем считать append следующим:

append [] ys = ys
append (x:xs) ys = x : append xs ys

В логическом программировании мы можем считать append следующим:

append([], Ys, Ys).
append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).

Они реализуют один и тот же алгоритм и даже работают в основном одинаково, но они "означают" что-то совсем другое.

Функциональный append определяет список, полученный из добавления ys в конец xs. Мы рассматриваем append как функцию из двух списков в другой список, а система времени исполнения предназначена для вычисления результата функции, когда мы вызываем ее в двух списках.

Логическая append определяет взаимосвязь между тремя списками, которая является истиной, если третий список - это элементы первого списка, за которыми следуют элементы второго списка. Мы полагаем, что append как предикат , который является либо истинным, либо ложным для любых 3 списков, а система выполнения предназначена для поиска значений, которые сделают этот предикат истинным, когда мы вызываем его с некоторыми аргументами привязаны к определенным спискам, а некоторые - к несвязанным.

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

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

Ответ 5

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

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

Ответ 6

Я думаю, что разница в этом:

  • императивное программирование = действия моделирования
  • программирование функций = моделирование
  • логическое программирование = знание моделирования

выберите то, что лучше всего подходит вашему уме

Ответ 7

функциональное программирование: когда 6PM, свет дальше. логическое программирование: когда темнота светится.