我听到这个术语在几个不同的背景下被提起。它是什么意思?
我听到这个术语在几个不同的背景下被提起。它是什么意思?
声明式编程是指以描述想要实现的功能为主,而非如何实现为主的代码编写方式。具体的实现方法由编译器确定。
声明式编程语言的例子包括SQL和Prolog。
其他回答已经很好地解释了什么是声明式编程,所以我将提供一些为什么这可能有用的例子。
声明式程序是上下文无关的。因为它们只声明最终目标,而不声明达到该目标的中间步骤,所以同一个程序可以在不同的上下文中使用。这对于命令式程序来说很难做到,因为它们通常依赖于上下文(例如隐藏状态)。
以yacc
为例。它是一个解析器生成器,也就是编译器编译器,是一种外部声明式DSL,用于描述语言的语法,从而可以从描述中自动生成该语言的解析器。由于其上下文无关性,您可以使用这样的语法做许多不同的事情:
yacc
的原始用例)yacc
源文件进行一些漂亮的打印、格式化和语法高亮处理,并将其包含在您的参考手册中,作为您的语言的语法规范。还有许多其他用途…
简而言之:
声明式编程倾向于:
命令式编程倾向于:
因此,命令式风格帮助读者理解系统实际执行的机制,但可能很少揭示它的目的。另一方面,声明式风格有助于读者理解问题领域和系统解决问题的方法,但在机制方面的信息较少。
真正的程序(即使是使用偏向于某一端的语言编写的程序,如ProLog或C),在不同的点上以不同程度地同时具备这两种风格,以满足作品的各种复杂性和沟通需求。一种风格不比另一种更优越;它们只是服务于不同的目的,就像生活中的许多事情一样,适度才是关键。
这里有一个例子。
在用于样式化HTML页面的CSS中,如果您想要一个图像元素高度为100像素,宽度为100像素,您只需"声明"您想要的大小,如下所示:
#myImageId {
height: 100px;
width: 100px;
}
你可以把 CSS 视为一种声明性的“样式表”语言。
解释这个 CSS 的浏览器引擎可以自由地使图像以任何它想要的高度和宽度显示。不同的浏览器引擎(例如,IE 的引擎、Chrome 的引擎)会以不同的方式实现此任务。
当然,它们独特的实现并不是用声明性语言编写的,而是用程序化语言,如 Assembly、C、C++、Java、JavaScript 或 Python 编写的。那些代码是一堆要一步一步执行的步骤(可能包括函数调用)。它可能做像插值像素值和渲染到屏幕上这样的事情。很抱歉,我必须反对其他答案中的许多观点。我希望停止混淆声明式编程定义的误解。
定义
参考透明度(RT)是声明式编程表达式的唯一必需属性,因为它是与命令式编程不共享的唯一属性。
其他引用的声明性编程属性来源于此参考透明度。请单击上面的超链接以获取详细说明。
电子表格示例
有两个答案提到了电子表格编程。在电子表格编程(即公式)不访问可变全局状态的情况下,则属于声明式编程。这是因为可变单元格值是main()
(整个程序)的单一输入和输出。在执行电子表格中的所有公式期间,新值不会在每次执行公式后写入单元格,因此它们在声明式程序的生命周期内不可变(执行电子表格中的所有公式)。因此,相对于彼此,这些公式将这些可变单元格视为不可变的。RT函数可以访问不可变的全局状态(以及可变的本地状态)。
因此,当程序终止时可以更改单元格中的值(作为main()
的输出),但这不会使它们成为上下文中可变的存储值。关键区别在于单元格值在执行每个电子表格公式后未更新,因此执行公式的顺序无关紧要。只有在所有声明性公式执行完毕后,才会更新单元格值。
向计算机描述您想要的内容,而不是如何做某件事。
自从2011年12月我提供了一个答案以来,我已经完善了对声明式编程的理解。以下是我的当前理解。
我的理解(研究)的详细版本在这个链接中详细说明,您应该阅读它以深入了解我将在下面提供的摘要。
命令式编程是存储和读取可变状态的地方,因此程序指令的排序和/或复制可以改变程序的行为(语义),甚至可能导致错误(即意外行为)。
在最天真和极端的意义上(我在之前的答案中断言过),声明式编程(DP)避免所有存储的可变状态,因此程序指令的排序和/或复制不能改变程序的行为(语义)。
然而,在现实世界中,这样极端的定义并不是很有用,因为几乎每个程序都涉及存储的可变状态。 电子表格示例 符合DP的这种极端定义,因为整个程序代码在使用一个静态副本的输入状态完成后运行到完成,然后存储新状态。然后,如果更改任何状态,则会重复此过程。但大多数现实世界的程序无法局限于这样的状态更改单一模型。函数式编程
是当今的热词,本质上是声明式编程的子集。在C#语言中,LINQ是函数式编程的一个元素,尽管该语言本质上是命令式的。因此,根据这个定义,C#变成了一种混合型语言。 - RBT