我知道声明式编程只是传递输入并期望输出,而没有说明过程是如何完成的。在函数式编程中,是一种编程范式,它接受输入并返回输出。当我检查高阶函数编程时,我们传递了一个函数来映射/减少,它没有揭示它是如何完成的过程。那么高阶函数式编程和声明式编程是一回事吗?
简短回答:否。
维基百科将 声明式编程定义为:
在计算机科学中,声明式编程是一种编程 范式 - 一种构建计算机结构和元素的风格 程序 -表达计算的逻辑而不描述 其控制流。
或者大胆地说:"说你想说的,而不是你想要的。
因此,这与命令式编程语言形成鲜明对比,在命令式编程语言中,程序被视为一组一个接一个完成的指令。map
等不显示过程的事实并不能使它成为声明性的:可以使用许多专有的 C 库,并且不允许您检查源代码。然而,这并不意味着这些是声明性的。
另一方面,函数式编程的定义是:
在计算机科学中,函数式编程是一种编程范式 - 一种构建计算机程序结构和元素的风格 - 将计算视为数学函数的评估,避免改变状态和可变数据。它是一个声明式的 编程范式,这意味着编程是用表达式完成的 或声明而不是语句。
基于这些定义,可以说函数式编程是声明式编程的一个子集。然而,在实际意义上,如果我们遵循严格的定义,现在没有一种编程语言是纯粹的、明确的声明式或函数式的。然而,人们可以说Haskell比Java更具声明性。
声明式编程通常被认为是"更安全"的,因为人们往往难以管理副作用。许多编程错误都是没有考虑所有副作用的结果。另一方面,很难
- 设计一种语言,允许程序员描述他想要的东西,而无需详细说明如何做到这一点; 实现
- 一个编译器,该编译器将基于此类程序生成有效的实现;以及
- 有些问题有固有的副作用。例如,如果您使用数据库,网络连接或文件系统,那么读取/写入文件应该会产生副作用。当然,人们可以决定不将这部分作为编程语言的一部分(例如,许多约束编程语言不允许这些类型的操作,并且是更大系统中的"子语言")。
已经有几次尝试设计这样的语言。在我看来,最受欢迎的是逻辑编程、函数式编程和约束编程。每个都有其优点和问题。我们还可以在例如数据库(如SQL)和文本/XML处理(使用XSLT,XPath,正则表达式,...)中观察到这种声明性方法,其中不指定如何解析查询,而只是通过例如正则表达式指定要查找的内容。
然而,编程语言是否是声明性的,是一个模糊的讨论。虽然编程语言,建模语言和库如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)
将返回False
而is_empty2 (repeat 0)
将永远循环。因此,这意味着我们仍然以某种方式将一些"控制流"写入程序:我们已经在某种程度上定义了Haskell应该如何评估这一点。虽然惰性编程会导致程序员并没有真正指定应该首先评估什么,但仍然有规范Haskell将如何评估这一点。
根据一些人的说法,这是编程和指定之间的区别。我的一位教授曾经说过,根据他的说法,区别在于,当你对某物进行编程时,你可以以某种方式控制如何评估某物,而当你指定某物时,你无法控制。但同样,这只是众多定义之一。
不完全是,函数式编程更强调计算什么,而不是如何计算。但是,函数式编程中有一些可用的模式,这些模式几乎是通常与声明式编程相关联的控制流模式,例如以下控制流:
let continue = ref true in
while !continue do
...
if cond then continue := false
else
...
done
看起来很熟悉吧?在这里,您可以看到一些声明性构造,但这一次我们可以更好地控制。