函数式编程是一种声明式编程吗?

Is functional programming a type of declarative programming?

我知道声明式编程只是传递输入并期望输出而不说明过程是如何完成的。在函数式编程中,是一种编程范例,它接受输入和 returns 输出。当我检查高阶函数编程时,我们将一个函数传递给 map/reduce,这并没有揭示它是如何完成的。那么高阶函数式编程和声明式编程是一回事吗??

简答

维基百科declarative programming 定义为:

In computer science, declarative programming is a programming paradigm - a style of building the structure and elements of computer programs - that expresses the logic of a computation without describing its control flow.

或者说得大胆一点:"Say what you want, not how you want it.".

因此,这与 命令式[​​=87=] 编程语言形成对比,在后者中,程序被视为一个接一个执行的 指令集 . map 不公开过程这一事实 并不能使其具有声明性:可以使用许多专有的 C 库,不允许您检查源代码。然而,这并不意味着这些是声明性的。

另一方面functional programming的定义是:

In computer science, functional programming is a programming paradigm - a style of building the structure and elements of computer programs - that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions or declarations instead of statements.

基于这些定义,可以说 函数式编程是声明式编程的一个子集。然而,在实际意义上,如果我们遵循 strict 定义,现在没有任何一种编程语言是纯粹的、明确的 declarative功能。然而,可以说 Haskell 比 Java.

更具 声明性

声明式编程通常被认为是 "safer",因为人们往往难以管理副作用。很多编程错误都是由于没有考虑到所有的副作用造成的。另一方面很难

  1. 设计一种语言,它允许程序员描述他想要什么,而无需详细说明如何如何去做;
  2. 实现一个编译器,它会基于这样的程序生成一个高效实现;和
  3. 一些问题具有固有的副作用。例如,如果您使用数据库、网络连接或文件系统,那么对文件 reading/writing 应该会有副作用。人们当然可以决定不将这部分作为编程语言(例如,许多约束编程语言不允许这些类型的操作,并且在更大的系统中是 "sub language")。

已经有几次尝试设计这样的语言。在我看来,最流行的是 逻辑编程函数式编程约束编程。每个都有其优点和问题。我们还可以在 数据库 (如 SQL)和 text/XML 处理(使用 XSLTXPath, 正则表达式,...) 其中 not 指定如何解析查询,但只需通过例如正则表达式指定正在寻找的内容。

编程语言是否是声明式的,这是一个有点模糊的讨论。尽管 Haskell、Prolog、Gecode 等编程语言、建模语言和库确实使编程更具声明性,但从最严格的意义上讲,这些可能并不是声明性的。在最严格的意义上,人们应该认为无论如何编写逻辑,编译器总是会得出相同的结果(尽管它可能需要更长的时间)。

例如,我们要检查 Haskell 中的列表是否为空。我们可以这样写:

is_empty1 :: [a] -> Bool
is_empty1 [] = True
is_empty1 (_:_) = False

不过我们也可以这样写:

is_empty2 :: [a] -> Bool
is_empty2 l = length l == 0

对于相同的查询,两者应该给出相同的结果。然而,如果我们给它一个无限列表,is_empty1 (repeat 0) 将 return Falseis_empty2 (repeat 0) 将永远循环。所以这意味着我们仍然以某种方式将一些 "control flow" 写入程序:我们已经定义 - 在某种程度上 - 如何 Haskell 应该对此进行评估。尽管惰性编程会导致程序员并没有真正指定应该首先评估什么,但仍然有规范 Haskell 将如何评估它。

根据一些人的说法,这就是编程指定之间的区别。我的一位教授曾经说过,根据他的说法,不同之处在于,当你编写某些东西时,你可以以某种方式控制如何 某些东西被评估,而当你指定有些东西,你管不着。但同样,这只是众多定义中的 一个

不完全是,函数式编程更强调计算什么而不是如何计算。然而,在函数式编程中有一些可用的模式,它们几乎是您通常会与声明式编程相关联的控制流模式,例如以下控制流:

let continue = ref true in
while !continue do
  ...
  if cond then continue := false
  else
     ...
done

看起来很眼熟吧?在这里您可以看到一些声明性结构,但这次我们控制得更多。