什么是声明性编程?

时间:2008-09-24 20:15:27

标签: programming-languages declarative glossary

我一直听到这个词在几个不同的背景下被抛出。它是什么?

17 个答案:

答案 0 :(得分:131)

声明性编程是指您编写代码时,它描述了您想要执行的操作,而不是您想要执行的操作。它由编译器来决定如何。

声明性编程语言的示例是SQL和Prolog。

答案 1 :(得分:74)

其他答案已经很好地解释了声明性编程是什么,所以我只是提供一些可能有用的例子。

上下文独立

声明性程序与上下文无关。因为它们只声明最终目标是什么,而不是实现该目标的中间步骤,所以可以在不同的上下文中使用相同的程序。这对于命令式程序很难,因为它们通常依赖于上下文(例如隐藏状态)。

yacc为例。它也是一个解析器生成器。编译器编译器,用于描述语言语法的外部声明性DSL,以便可以从描述中自动生成该语言的解析器。由于它的上下文独立性,你可以用这样的语法做很多不同的事情:

  • 为该语法生成​​C语法分析器(yacc的原始用例)
  • 为该语法生成​​C ++解析器
  • 为该语法生成​​Java解析器(使用Jay)
  • 为该语法生成​​一个C#解析器(使用GPPG)
  • 为该语法生成​​一个Ruby解析器(使用Racc)
  • 为该语法生成​​树形可视化(使用GraphViz)
  • 只需对yacc源文件本身进行一些漂亮的打印,花式格式化和语法高亮显示,并将其作为语言的语法规范包含在参考手册中

还有更多......

优化

因为您没有规定计算机采取的步骤以及采用何种顺序,所以它可以更自由地重新安排程序,甚至可以并行执行某些任务。一个很好的例子是SQL数据库的查询规划器和查询优化器。大多数SQL数据库允许您显示他们实际执行的查询与您要求执行的查询。通常,这些查询看起来像彼此 。查询规划器会考虑到您甚至没有想到的事情:例如,磁盘盘片的旋转延迟,或者完全不同的用户执行类似查询的一些完全不同的应用程序以及您所使用的表格这一事实加入并且你努力工作以避免加载已经在内存中了。

这里有一个有趣的权衡:机器必须更加努力地找出如何做一些事情,而不是命令式语言,但当它做弄明白,它为优化阶段提供了更多的自由和更多的信息。

答案 2 :(得分:18)

松散:

声明式编程倾向于: -

  • 声明或声明性声明的集合,每个声明或声明性声明都有意义(通常在问题域中),可以独立理解,也可以单独理解。

势在必行的编程倾向于: -

  • 命令序列,每个命令执行一些操作;但在问题领域可能有意义,也可能没有意义。

因此,命令式样式有助于读者理解系统实际执行的操作的机制,但可能无法深入了解它要解决的问题。另一方面,声明式风格有助于读者理解问题领域和系统解决问题所采用的方法,但在力学问题上信息量较少。

真实节目(即使用有利于频谱末端的语言编写的节目,如ProLog或C)往往会在不同的点上呈现不同程度的两种风格,以满足作品的不同复杂性和通信需求。一种风格并不优于另一种风格;它们只是用于不同的目的,而且,与生活中的许多事情一样,适度是关键。

答案 3 :(得分:12)

我很抱歉,但我必须不同意其他许多答案。我想停止对声明性编程定义的这种混乱的误解。

<强>定义

Referential transparency (RT) of the sub-expressions is the only required attribute of a declarative programming expression,因为它是唯一不与命令式编程共享的属性。

声明性编程的其他引用属性,源自此RT。请点击上面的超链接获取详细说明。

电子表格示例

两个答案提到电子表格编程。在电子表格编程(a.k.a.公式)不访问可变全局状态的情况下,则它是声明性编程。这是因为可变单元格值是main()(整个程序)的单片输入输出。执行每个公式后,新值不会写入单元格,因此它们在声明性程序的生命周期内不可变(执行电子表格中的所有公式)。因此,相对于彼此,公式将这些可变细胞视为不可变的。允许RT函数访问不可变的全局状态(以及mutable local state)。

因此,当程序终止时(作为main()的输出)突变单元格中的值的能力不会使它们在规则的上下文中成为可变的存储值。关键的区别是在执行每个电子表格公式后不更新单元格值,因此执行公式的顺序无关紧要。在执行所有声明性公式后更新单元格值。

答案 4 :(得分:8)

以下是一个例子。

在CSS(用于设置HTML页面样式)中,如果您希望图像元素高100像素,宽100像素,您只需“声明”您想要的内容如下:

#myImageId {
height: 100px;
width: 100px;
}

您可以将CSS视为声明性的“样式表”语言。

读取和解释这个CSS的浏览器引擎可以自由地使图像看起来很高,但它想要这么宽。不同的浏览器引擎(例如,用于IE的引擎,用于Chrome的引擎)将以不同方式实现该任务。

当然,它们的独特实现不是用声明性语言编写的,而是用程序式编写的,如Assembly,C,C ++,Java,JavaScript或Python。该代码是一系列逐步执行的步骤(可能包括函数调用)。它可能会执行内插像素值和在屏幕上渲染等内容。

答案 5 :(得分:7)

声明性编程就是图片,其中命令式编程是绘制图片的指令。

如果你“告诉它它是什么”,你就会以声明式的方式写作,而不是描述计算机应该走到你想要的地方的步骤。

当您使用XML标记数据时,您正在使用声明性编程,因为您说的是“这是一个人,这是一个生日,并且有一个街道地址”。

将声明性和命令式编程结合起来以获得更大效果的一些示例:

  • Windows Presentation Foundation使用声明性XML语法来描述用户界面的外观,以及控件与底层数据结构之间的关系(绑定)。

  • 结构化配置文件使用声明性语法(就像“key = value”对一样简单)来标识字符串或数据值的含义。

  • HTML使用标记来标记文本,这些标记描述了每段文本相对于整个文档的作用。

答案 6 :(得分:6)

想象一下excel页面。使用填充公式的列来计算纳税申报表。

所有逻辑都在单元格中声明完成,计算的顺序由公式本身确定,而不是在程序上确定。

这就是声明式编程的全部内容。您声明问题空间和解决方案而不是程序流。

Prolog是我使用的唯一声明性语言。它需要一种不同的思维方式,但是如果只是为了让你接触到除了典型的过程式编程语言之外的其他东西,这是很好的。

答案 7 :(得分:5)

这是一种编程方法,它基于描述应该做什么或什么而不是描述 应该如何工作。

换句话说,你不编写由表达式组成的算法,你只需要布局你想要的东西。两个很好的例子是HTML和WPF。

这篇维基百科文章是一个很好的概述:http://en.wikipedia.org/wiki/Declarative_programming

答案 8 :(得分:5)

声明性编程是使用声明进行编程,即声明性句子。陈述句有许多属性,可以将它们与命令式句子区分开来。特别是,声明是:

  • 可交换(可重新订购)
  • associative(可以重新组合)
  • 幂等(可以在不改变意义的情况下重复)
  • 单调(声明不减去信息)

一个相关的观点是,这些都是结构性质,与主题正交。声明不是关于“What vs. How”。我们可以像声明“what”一样轻松地声明(表示和约束)“how”声明是关于结构,而不是内容。声明性编程对我们如何抽象和重构代码以及如何将其模块化为子程序产生重大影响,但对域模型的影响不大。

通常,我们可以通过添加上下文从命令转换为声明。例如。从“向左转。(......等待......)向右转。” “鲍勃将于11:01在Foo和Bar的十字路口左转。鲍勃将于11:06在Bar和Baz的交叉路口右转。”请注意,在后一种情况下,句子是幂等的和可交换的,而在前一种情况下,重新排列或重复句子会严重改变程序的含义。

关于 monotonic ,声明可以添加约束,减去的可能性。但约束仍然增加信息(更确切地说,约束是信息)。如果我们需要时变声明,通常用显式时间语义对其进行建模 - 例如从“球是平的”到“球在时间T是平的”。如果我们有两个相互矛盾的声明,我们就会有一个不一致的声明系统,尽管这可以通过引入 soft 约束(优先级,概率等)或利用一个不一致的逻辑来解决。

答案 9 :(得分:5)

自2011年12月我提出an answer这个问题以来,我已经完善了对声明性编程的理解。以下是我目前的理解。

我的理解(研究)的长版本详见 this link ,您应该阅读以深入理解我将在下面提供的摘要。

命令式编程是存储和读取可变状态的地方,因此程序指令的排序和/或复制可能会改变程序的行为(语义)(甚至会导致错误,即意外行为)。

在最天真和极端的意义上(我在之前的回答中断言),声明性编程(DP)避免了所有存储的可变状态,因此程序指令的排序和/或重复可以 NOT 改变程序的行为(语义)。

然而,这样的极端定义在现实世界中并不是非常有用,因为几乎每个程序都涉及存储的可变状态。 spreadsheet example符合DP的这种极端定义,因为在存储新状态之前,整个程序代码使用输入状态的一个静态副本运行完成。然后,如果任何状态改变,则重复此操作。但是大多数现实世界的程序不能局限于这种状态变化的单一模型。

DP的更有用的定义是编程指令的排序和/或重复不会改变任何不透明的语义。换句话说,语义中没有隐藏的随机变化 - 程序指令顺序和/或重复的任何变化都只会导致程序行为的预期和透明变化。

下一步将讨论哪些编程模型或范例对DP有帮助,但这不是问题。

答案 10 :(得分:4)

向计算机描述您想要的内容,而不是如何做某事。

答案 11 :(得分:3)

声明性编程是“符合开发人员心理模型的语言编程行为,而不是机器的操作模型”。

声明式编程和命令式编程之间的区别很好 由解析结构化数据的问题说明。

命令式程序将使用相互递归函数来消耗输入 并生成数据。声明性程序将表达定义的语法 数据的结构,以便可以解析它。

这两种方法的区别在于声明性程序 创建一种更接近地映射到心智模型的新语言 问题而不是它的主语。

答案 12 :(得分:2)

这可能听起来很奇怪,但我会将Excel(或任何电子表格)添加到声明系统列表中。一个很好的例子就是here

答案 13 :(得分:1)

我会解释它,因为DP是一种表达方式

  • 目标表达式,条件 - 我们正在搜索的内容。有一个,可能还是很多?
  • 一些已知事实
  • 扩展已知事实的规则

...并且有一个扣除引擎通常使用统一算法来查找目标。

答案 14 :(得分:-1)

据我所知,它开始被用来描述像Prolog这样的编程系统,因为prolog(据说)是以抽象的方式声明事物。

它越来越意味着很少,因为它具有上述用户给出的定义。应该清楚的是,Haskell的声明性编程与HTML的声明性编程之间存在鸿沟。

答案 15 :(得分:-2)

声明性编程的其他几个例子:

  • 用于数据绑定的ASP.Net标记。例如,它只是说“使用此源填充此网格”,并将其留给系统以了解其发生的方式。
  • Linq表达

声明性编程很好,因为它可以帮助simplify your mental model *代码,并且因为它最终可能更具可伸缩性。

例如,假设您有一个函数可以对数组或列表中的每个元素执行某些操作。传统代码如下所示:

foreach (object item in MyList)
{
   DoSomething(item);
}

没什么大不了的。但是,如果您使用更具声明性的语法并将DoSomething()定义为Action,该怎么办?然后你可以这样说:

MyList.ForEach(DoSometing);

这当然更简洁。但我相信你有更多的顾虑,而不仅仅是在这里和那里保存两行代码。例如,表现。旧的方式,处理必须按顺序进行。如果.ForEach()方法有办法让你发出信号表明它可以自动并行处理处理怎么办?现在,你突然间以非常安全的方式使代码多线程化,只改变了一行代码。事实上,.Net有一个extension可以让你做到这一点。

  • 如果您关注该链接,则会将您带到我的朋友的博客文章中。整个帖子有点长,但你可以向下滚动到标题为“问题”的标题_并在那里找到它没有问题。*

答案 16 :(得分:-3)

这取决于您如何提交文本的答案。总的来说,您可以在某个视图中查看该程序,但这取决于您对问题的看法。我会帮你开始这个项目: 昏暗的巴士,汽车,时间,高度作为整合者

同样,这取决于整体问题。由于程序的原因,您可能需要缩短它。希望这有帮助,如果没有,则需要反馈。 谢谢。