我一直在阅读许多文章,试图理解函数式编程和逻辑编程之间的区别,但到目前为止,我唯一能做的推论是,逻辑编程通过数学表达式定义程序。但这样的事情与逻辑编程无关。
对于函数式编程和逻辑编程之间的区别,我真的很感激。
发布于 2011-11-28 23:15:30
我不会说逻辑编程通过数学表达式定义程序;这听起来更像是函数式编程。逻辑编程使用逻辑表达式(好吧,逻辑最终是数学)。
在我看来,函数式编程和逻辑编程之间的主要区别在于“构建块”:函数式编程使用函数,而逻辑编程使用谓词。谓词不是函数;它没有返回值。根据其参数的值,它可能是true或false;如果一些值未定义,它将尝试找到使谓词为true的值。
Prolog特别使用了一种特殊形式的逻辑子句,称为Horn clauses,属于一阶逻辑;Hilog使用更高阶逻辑的子句。
当你写一个prolog谓词时,你是在定义一个horn子句:foo :- bar1, bar2, bar3.意味着如果bar1,bar2和bar3为真,foo也为真。请注意,我没有说if和only if;一个谓词可以有多个子句:
foo:-
bar1.
foo:-
bar2.表示如果bar1为true或bar2为true,foo为true
有人说逻辑编程是函数式编程的超集,因为每个函数都可以表示为谓词:
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点时失败,但不会收到错误;Prolog将尝试第二个子句并返回R = 3。
我不认为函数式语言实现类似的东西是不可能的(但我没有使用过这样的语言)。
总而言之,尽管这两种范式都被认为是声明性的,但它们是完全不同的;如此不同,以至于比较它们就像是比较函数式和命令式风格。我建议尝试一下逻辑编程;这应该是一次令人难以置信的经历。但是,您应该尝试理解其中的原理,而不是简单地编写程序;Prolog允许您以函数式甚至命令式的方式编写(具有可怕的结果)。
发布于 2011-11-28 23:11:12
简而言之:
在函数式编程中,您的程序是一组函数定义。每个函数的返回值都作为数学表达式进行计算,可能会使用传递的参数和其他定义的函数。例如,您可以定义一个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”谓词,只要第二个参数是first的阶乘,它就会成立:
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这两种样式都允许在程序中使用数学表达式。
发布于 2011-11-29 02:30:33
首先,函数式编程和逻辑编程之间有很多共同点。也就是说,在一个社区中开发的许多概念也可以在另一个社区中使用。这两种范例都是从相当粗糙的实现开始的,并努力追求纯洁性。
但是你想知道它们之间的区别。
所以我会把Haskell放在一边,把Prolog和约束放在另一边。实际上,所有当前的Prolog系统都提供了某种约束,如B、Ciao、ECLiPSe、GNU、IF、Scryer、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个元素:
> take 4 v
[[1,2,3],[2,3],[3],[]]请注意,函数式程序中的语法受到了巧妙的限制,以避免变量未定义。
在逻辑编程中,变量不需要引用具体的值。因此,如果我们想要一个包含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来说,最早的建议可以追溯到20世纪80年代初,但仍然不是很常见。至少ISO Prolog现在有了要应用的同源物,称为call/2, call/3 ...。
Lambdas:同样,可以在这个方向上扩展逻辑编程,最突出的系统是Lambda Prolog。最近,lambdas也被开发出来了,for ISO Prolog。
类型系统:已经有人尝试过了,比如“水星”,但它还没有流行起来。而且没有一个系统的功能可以与类型类相媲美。
纯度: Haskell是完全纯的,一个函数整型->是一个函数。周围没有精美的印刷品。而且你仍然可以表现出副作用。可比较的方法发展非常缓慢。
在许多领域,函数式编程和逻辑编程或多或少存在重叠。例如,回溯、懒惰和列表理解、懒惰评估和freeze/2、when/2、block。DCGs和monads。我会把这些问题留给其他人来讨论。
https://stackoverflow.com/questions/8297574
复制相似问题