首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >逻辑编程与函数式编程的区别

逻辑编程与函数式编程的区别
EN

Stack Overflow用户
提问于 2011-11-28 22:48:31
回答 8查看 32.5K关注 0票数 77

我一直在阅读许多文章,试图理解函数式编程和逻辑编程之间的区别,但到目前为止,我唯一能做的推论是,逻辑编程通过数学表达式定义程序。但这样的事情与逻辑编程无关。

对于函数式编程和逻辑编程之间的区别,我真的很感激。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 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;一个谓词可以有多个子句:

代码语言:javascript
复制
foo:-
   bar1.
foo:-
  bar2.

表示如果bar1为true或bar2为true,foo为true

有人说逻辑编程是函数式编程的超集,因为每个函数都可以表示为谓词:

代码语言:javascript
复制
foo(x,y) -> x+y.

可以写成

代码语言:javascript
复制
foo(X, Y, ReturnValue):-
   ReturnValue is X+Y.

但我认为这样的说法有点误导。

逻辑和函数之间的另一个区别是回溯。在函数式编程中,一旦进入函数体,就不能失败并转到下一个定义。例如,您可以编写

代码语言:javascript
复制
abs(x) -> 
   if x>0 x else -x

或者甚至使用守卫:

代码语言:javascript
复制
abs(x) x>0 -> x;
abs(x) x=<0 -> -x.

但是你不能写

代码语言:javascript
复制
abs(x) ->
   x>0,
   x;
abs(x) ->
   -x.

另一方面,在Prolog中你可以这样写

代码语言:javascript
复制
abs(X, R):-
   X>0,
   R is X.
abs(X, R):-
   R is -X.

如果调用abs(-3, R),Prolog将尝试第一个子句,并在执行到达-3 > 0点时失败,但不会收到错误;Prolog将尝试第二个子句并返回R = 3

我不认为函数式语言实现类似的东西是不可能的(但我没有使用过这样的语言)。

总而言之,尽管这两种范式都被认为是声明性的,但它们是完全不同的;如此不同,以至于比较它们就像是比较函数式和命令式风格。我建议尝试一下逻辑编程;这应该是一次令人难以置信的经历。但是,您应该尝试理解其中的原理,而不是简单地编写程序;Prolog允许您以函数式甚至命令式的方式编写(具有可怕的结果)。

票数 68
EN

Stack Overflow用户

发布于 2011-11-28 23:11:12

简而言之:

在函数式编程中,您的程序是一组函数定义。每个函数的返回值都作为数学表达式进行计算,可能会使用传递的参数和其他定义的函数。例如,您可以定义一个factorial函数,该函数返回给定数字的阶乘:

代码语言:javascript
复制
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的阶乘,它就会成立:

代码语言:javascript
复制
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

这两种样式都允许在程序中使用数学表达式。

票数 30
EN

Stack Overflow用户

发布于 2011-11-29 02:30:33

首先,函数式编程和逻辑编程之间有很多共同点。也就是说,在一个社区中开发的许多概念也可以在另一个社区中使用。这两种范例都是从相当粗糙的实现开始的,并努力追求纯洁性。

但是你想知道它们之间的区别。

所以我会把Haskell放在一边,把Prolog和约束放在另一边。实际上,所有当前的Prolog系统都提供了某种约束,如B、Ciao、ECLiPSe、GNU、IF、Scryer、SICStus、SWI、YAP、XSB。为了便于讨论,我将使用一个非常简单的约束dif/2来表示不平等,它甚至在第一个Prolog实现中就存在-所以我不会使用比它更高级的任何东西。

函数式编程缺少什么

最根本的区别在于变量的概念。在函数式编程中,变量表示一个具体的值。该值不能完全定义,但只有定义的部分才能在计算中使用。在Haskell中考虑:

代码语言:javascript
复制
> let v = iterate (tail) [1..3] 
> v
[[1,2,3],[2,3],[3],[],*** Exception: Prelude.tail: empty list

在第四个元素之后,值是未定义的。不过,您可以安全地使用前4个元素:

代码语言:javascript
复制
> take 4 v
[[1,2,3],[2,3],[3],[]]

请注意,函数式程序中的语法受到了巧妙的限制,以避免变量未定义。

在逻辑编程中,变量不需要引用具体的值。因此,如果我们想要一个包含3个元素的列表,我们可以这样说:

代码语言:javascript
复制
?- length(Xs,3).
Xs = [_G323, _G326, _G329].

在这个答案中,列表的元素是变量。这些变量的所有可能实例都是有效的解决方案。比如Xs = [1,2,3]。现在,假设第一个元素应该与其余元素不同:

代码语言:javascript
复制
?- length(Xs,3), Xs = [X|Ys], maplist(dif(X), Ys).
Xs = [X, _G639, _G642],
Ys = [_G639, _G642],
dif(X, _G642),
dif(X, _G639).

稍后,我们可能会要求Xs中的元素都是相等的。在我把它写出来之前,我将单独尝试一下:

代码语言:javascript
复制
?- maplist(=(_),Xs).
Xs = [] ;
Xs = [_G231] ;
Xs = [_G231, _G231] ;
Xs = [_G231, _G231, _G231]  ;
Xs = [_G231, _G231, _G231, _G231] .

看到答案总是包含相同的变量了吗?现在,我可以组合这两个查询:

代码语言:javascript
复制
?- length(Xs,3), Xs = [X|Ys], maplist(dif(X), Ys), maplist(=(_),Xs).
false.

所以我们在这里展示的是,没有3个元素列表,其中第一个元素与其他元素不同,并且所有元素都是相等的。

这种通用性允许开发出几种约束语言,它们作为库提供给Prolog系统,其中最突出的是CLPFDCHR

在函数式编程中没有直接获得类似功能的方法。您可以模拟一些东西,但模拟并不完全相同。

缺少什么逻辑编程

但是,逻辑编程中缺少的许多东西使函数式编程变得如此有趣。特别是:

高阶编程:函数式编程在这里有很长的传统,并开发了一组丰富的习惯用法。对于Prolog来说,最早的建议可以追溯到20世纪80年代初,但仍然不是很常见。至少ISO Prolog现在有了要应用的同源物,称为call/2, call/3 ...

Lambdas:同样,可以在这个方向上扩展逻辑编程,最突出的系统是Lambda Prolog。最近,lambdas也被开发出来了,for ISO Prolog

类型系统:已经有人尝试过了,比如“水星”,但它还没有流行起来。而且没有一个系统的功能可以与类型类相媲美。

纯度: Haskell是完全纯的,一个函数整型->是一个函数。周围没有精美的印刷品。而且你仍然可以表现出副作用。可比较的方法发展非常缓慢。

在许多领域,函数式编程和逻辑编程或多或少存在重叠。例如,回溯、懒惰和列表理解、懒惰评估和freeze/2when/2block。DCGs和monads。我会把这些问题留给其他人来讨论。

票数 24
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8297574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档