我知道声明式编程只是传递输入并期望输出,而不陈述它是如何完成的过程。在函数式编程中,这是一种编程范式,它接受输入并返回输出。当我检查高阶函数式编程时,我们将函数传递给map/reduce,但没有揭示它是如何完成的过程。那么高阶函数式编程和声明式编程是否相同?
我知道声明式编程只是传递输入并期望输出,而不陈述它是如何完成的过程。在函数式编程中,这是一种编程范式,它接受输入并返回输出。当我检查高阶函数式编程时,我们将函数传递给map/reduce,但没有揭示它是如何完成的过程。那么高阶函数式编程和声明式编程是否相同?
简短回答: 不是。
维基百科将声明式编程定义为:
在计算机科学中,声明式编程是一种编程范例——一种构建计算机程序结构和元素的方式,它表达了计算逻辑而不描述其控制流程。
或者更大胆地说:“说出你想要的,而不是你想要的方法。”。
这与命令式编程语言形成对比,在其中,程序被看作是一系列指令依次执行。虽然map
等函数“不显示过程”,但这并不意味着它具备声明式:你可以使用许多C库,这些库是专有的,不允许您检查源代码。然而,这并不意味着它们是声明性的。
另一方面,函数式编程的定义是:
在计算机科学中,函数式编程是一种编程范式——一种构建计算机程序结构和元素的方式,它将计算视为数学函数的评估,并避免了更改状态和可变数据。它是一种声明式编程范式,这意味着使用表达式或声明进行编程,而不是语句。
基于这些定义,可以说函数式编程是声明式编程的一个子集。然而,在实际应用中,如果我们遵循严格的定义,现在没有一种编程语言是纯粹、明确的声明式编程或函数式编程。然而,可以说Haskell比Java更加声明性。
通常认为声明式编程更“安全”,因为人们往往难以管理副作用。许多编程错误是由于未考虑所有副作用而产生的。另一方面,做到以下几点很难:
已经有几个尝试设计这种语言的方法。最流行的是——在我看来——逻辑编程、函数式编程和约束编程。每种方法都有其优点和问题。我们还可以在数据库(如SQL)和文本/XML处理中观察到这种声明性方法(使用XSLTis_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
看起来很熟悉,对吧?在这里,您可以看到一些声明性结构,但这次我们有更多的控制。