我不断听到这个词扔在几个不同的上下文。这是什么?

有帮助吗?

解决方案

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

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

其他提示

其他的答案已经做了出色的工作说明什么样的说明性程序是,所以我只是要提供一些例子,为什么,可能是有用的。

上下文中的独立性

声明的程序 背景下独立.因为他们仅宣布什么最终目标是,但不是中介的步骤,以达到这一目标,同样的程序可以使用在不同的上下文中。这是很难做 必要的程序, 因为他们往往取决的上下文(例如隐藏的状态)。

yacc 作为一个例子。这是分析发电机又名。编译器编译器,一个外部声明的DSL用于描述语的语言,以便分析器,这一语言可以被自动产生的描述。由于其背景的独立,可以做许多不同的东西,用这样的语法:

  • 产生一个C分析器,这一文法(原来使用情况 yacc)
  • 产生一个C++分析器,语法
  • 产生Java分析器,这一文法(使用Jay)
  • 产生一个C#分析器,这一文法(使用GPPG)
  • 产生的红宝石的分析器,文法(使用的类别)
  • 产生一棵树可视为语法(使用GraphViz)
  • 只是做一些很漂亮-印刷、花式的格式和语法突出的yacc源文件本身和包括它在你的参考手册,作为语法规范的语言

更多...

优化

因为你没有规定计算机,其采取的步骤以及在什么样的顺序,就可以重新安排你的节目更多的自由,甚至可能执行一些任务并行。是一个很好的例子查询的规划和优化查询SQL数据库。最SQL数据库允许你来显示的查询,他们是 实际上 执行与查询你 要求 他们到执行。通常,这些查询看 没有什么 喜欢对方。查询规划需要的东西虑到,你甚至不会有想过:旋转的延迟盘盘,例如或事实上,一些完全不同的应用程序的一个完全不同的用户只是执行一个类似的查询,并表参与,你辛勤工作,以避免装载的是早已存在。

还有一个有趣的交易-这里:机器已经更加努力地工作来找出 如何 做的东西,它们在必要的语言,但是当它 图,这具有更自由和更多的信息对于优化阶段。

松:

说明性程序趋于:-

  • 集中的宣言或声明的发言,每一个都具有的意义(通常在问题领域)并且可以理解的独立和隔离。

必须编程趋于:-

  • 命令序列,每个执行某些行动;但这可能有或可能没有意义的问题领域。

因此,必须式帮助读者理解该机制的什么系统实际上这样做,但是可以给点深入了解的问题,它的目的是要解决。另一方面,一个声明风格有助于读者理解该问题的领域和方法的系统需要对这个问题的解决方案,但是较少的信息对该问题的机制。

真正的计划(甚至是那些书面语言有利于两端的频谱,例如序言或C)往往有两个样本不同程度的各点,以满足变化的复杂性和通信的需要。一种风格是不优于其他人;他们只是服务于不同的目的,并且,作为与生活中的许多事情,适度是关键。

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

<强>定义

子表达式的参照透明度(RT)是声明性编程表达式的仅需要属性,因为它是唯一不与命令式编程共享的属性。

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

电子表格示例

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

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

以下是一个例子。

在CSS(用于设置HTML页面样式)中,如果您希望图像元素高100像素,宽100像素,则只需“声明”即可。这就是你想要的如下:

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

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

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

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

说明性程序的画面,在那里必须编程指令,用于绘画,画面。

你写在一个声明风格如果你是"告诉它它是什么",而不是描述步骤计算机应该拿到你想要它。

当你使用XML标记数据的,你在使用说明性程序,因为你说"这是一个人,这是一个生日,和在有街道地址"。

一些例子里声明性和必要的编程得到结合进更大的效果:

  • Windows介绍基金会采用声明性XML语法描述的用户界面看起来就像,什么样的关系(绑定)之间控制和数据基础结构。

  • 结构配置文件使用声明性的语法(为简单的"key=value"对)确定什么是串或价值的数据的装置。

  • HTML文本标记与标签,描述了什么作用的各条文本已在关系到整个文件。

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

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

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

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

自从我写完之前的答案以来,我已经制定了新定义。我还将命令式编程定义为双重属性。

这个定义优于我之前回答中提供的定义,因为它简洁而且更通用。但这可能更难以理解,因为适用于编程和生活的不完备性定理的含义对于人类来说难以包裹其中。

引用的定义解释讨论了 pure 函数式编程在声明性编程中的作用。

  

声明与命令

     

声明性属性很奇怪,迟钝,难以捕捉到技术上精确的定义,这种定义仍然是一般的而不是含糊不清的,因为我们可以宣告程序的含义(也就是语义)而不会产生意外的一面,这是一种天真的概念。效果。意义表达与避免意外影响之间存在固有的张力,这种紧张实际上源于不完备性定理。

     

过于简单化,技术上不精确,并且通常不明确将声明定义为&#8220; &nbsp;做&#8221; 和命令式为 &#8220; 如何&NBSP;至&NBSP;做&#8221; 即可。一个含糊不清的案例是&#8220; 什么&#8221;是&#8220; 如何&#8221;在一个程序中输出一个程序&#8212;编译器。

     

显然,使语言图灵完成的无限递归也是类似于语义学&#8212;不仅在评价的句法结构中(a.k.a。操作语义学)。这在逻辑上类似于G&#246; del's定理&#8212; &#8220; 任何完整的公理系统也是不一致的&#8221;思考那句话的矛盾怪异!它也是一个演示语义表达式如何没有可证明的界限的例子,因此我们无法证明 2 一个程序(类似于它的语义)停止了,也就是Halting定理。

     

不完备性定理来源于我们宇宙的基本性质,正如热力学第二定律所述,<∞>熵(也就是独立可能性的#)永远趋向于最大化&#8221;。程序的编码和设计永远不会完成&#8212;它还活着!&#8212;因为它试图满足现实世界的需要,现实世界的语义总是在变化,趋向于更多的可能性。人类永远不会停止发现新事物(包括程序中的错误; - )。

     

要在这个没有边缘的奇怪宇宙中精确地和技术上捕捉上述理想的概念(思考那个!我们宇宙中没有&#8220;外部&#8221;)需要一个简洁但看似不简单的定义在深入解释之前听起来不正确。

     

定义:

     
    
         

声明性属性是指只能存在一组可以表达每种特定模块语义的语句。

         

命令性属性 3 是双重属性,其中语义在组成下不一致和/或可以用语句集的变体表示。

         
  
     

声明性的这种定义在语义范围内具有明显的 local ,这意味着它要求模块化语义保持其一致的含义,无论在 global 中实例化和使用它的位置和方式范围。因此,每个声明性模块化语义应该与所有可能的其他模块语义本质上正交&#8212;并且不是不可能的(由于不完整性定理)全局算法或用于见证一致性的模型,这也是&#8220; 更多并不总是更好 &#8221;作者:卡内基梅隆大学计算机科学教授罗伯特哈珀,标准ML的设计者之一。

     

这些模块化声明性语义的示例包括类别理论仿函数,例如 Applicative ,名义打字,名称空间,命名字段和wrt到语义的操作级别然后是纯函数式编程。

     

如此精心设计的声明性语言可以更清楚地表达意义虽然在可以表达的内容中有一些普遍性的丧失,但在内在一致性表达的内容上却有所收获。

     

上述定义的一个例子是电子表格程序单元格中的公式集合。当移动到不同的列和行单元时,预期不会给出相同的含义,即单元标识符改变。单元标识符是预期含义的一部分,而不是多余的。因此,每个电子表格结果都是唯一的w.r.t.到一组公式中的单元标识符。在这种情况下,一致的模块化语义是使用单元格标识符作为单元格公式的 pure 函数的输入和输出(见下文)。

     

超文本标记语言a.k.a. HTML&#8212;静态网页的语言&#8212;是一个高度(但不完美的 3 )声明性语言的例子(至少在HTML之前5)没有表达动态行为的能力。 HTML可能是最容易学习的语言。对于动态行为,JavaScript等命令式脚本语言通常与HTML结合使用。没有JavaScript的HTML符合声明性定义,因为每个名义类型(即标签)在语法规则内的组合下保持其一致的含义。

     

声明性的竞争定义是可交换 idempotent 语义语句的属性,即语句可以在不改变含义的情况下重新排序和复制。例如,如果这些名称是模块化的,那么可以重新排序和复制为命名字段赋值的语句而不改变程序的含义。任何隐含的订单。名称有时意味着订单,例如单元标识符包括它们的列和行位置&#8212;在电子表格上移动总数会改变其含义。否则,这些属性隐式地要求语义的全局一致性。通常不可能设计语句的语义,因此如果随机排序或重复,它们保持一致,因为顺序和重复是语义固有的。例如,语句&#8220; Foo存在&#8221; (或建筑)和&#8220; F.oo不存在&#8221; (和破坏)。如果考虑到预期语义的随机不一致性,那么人们接受这个定义对于声明性属性就足够了。从本质上讲,这个定义是一个通用的定义,因为它试图使语义与语义正交,即无视语义世界是动态无界的,并且无法在全局一致性中捕获这一事实。范例

     

要求较低级操作语义的(结构评估顺序)的可交换和幂等属性将操作语义转换为声明性本地化模块化语义,例如, 函数式编程(包括递归而不是命令式循环)。然后,实现细节的操作顺序不会影响(即将全局扩展到)更高级语义的一致性。例如,电子表格公式的评估顺序(理论上也是重复)并不重要,因为在计算完所有输出之前,输出不会复制到输入,即类似于纯函数。

     

C,Java,C ++,C#,PHP和JavaScript并不是特别声明的。   Copute的语法和Python的语法更具声明性耦合到   预期的结果,即一致的句法语义,消除了无关的,因此人们可以很容易   在他们忘记之后理解代码。 Copute和Haskell强制执行   操作语义的确定性并鼓励&#8220; 不要重复   自己&#8221; (DRY),因为他们只允许纯粹的功能范式。

     
     

2 即使我们可以证明其语义一个程序,例如使用Coq语言,这仅限于输入,并且输入永远不能捕获程序的所有语义&#8212;甚至不是图灵完整的语言,例如使用HTML + CSS,可以表达不一致的组合,因此具有未定义的语义。

     

3 许多解释错误地声称命令式编程只有语法上有序的语句。我澄清了这个命令式和函数式编程之间的混淆。例如,HTML语句的顺序不会降低其含义的一致性。


编辑:我发布了以下评论给Robert Harper的博客:

  
    

在函数式编程中......变量的变化范围是类型

  
     

取决于人们如何将功能与命令区分开来   编程,你的&#8216;可分配&#8217;在一个命令式的计划中也可能有   一种限制其可变性的类型。

     

我目前唯一欣赏功能的非混乱定义   编程是a)作为第一类对象和类型的函数,b)   对循环递归的偏好,和/或c)纯函数&#8212;即   那些不影响所需语义的函数

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

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

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

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

自2011年12月我提供答案以来,我已经完善了对声明性编程的理解。以下是我目前的理解。

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

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

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

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

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

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

说明性程序被编程的声明,即陈述句子。陈述句有一定数量的特性,区分它们必须句子。特别是,声明是:

  • 交换(可以被重新排序)
  • 缔(可以是重新组合)
  • 幂等的(可以重复却没有改变的意思)
  • 单(申报不减的信息)

一个相关的一点是,所有这些都是结构性和正交的主题。声明是不是 "什么大如何".我们可以声明(代表和限制)的一个 "如何" 只是作为容易,因为我们宣布 "什么". 声明是关于结构中,没有内容。 说明性程序已经产生重大影响,我们如何抽象和"重构"我们的代码,以及我们如何模块化它变成程序,但没有那么多的领域模型。

我们经常可以转换为必须声明通过加入的上下文。E.g。从"向左转。(...等待它...)把正确的。","鲍勃将左转交Foo和酒吧,上午11:01.鲍勃会把权利交叉口的酒吧和巴兹在11:06." 注意在后一种情况下句子是幂等和交换,而在前一种情况下重新安排或重复的句子会严重改变的含义的程序。

关于 单调, 声明可以加入 限制 其中减去的 可能性.但限制仍然增加信息(更确切地说,限制信息)。如果我们需要时间变化的宣言,这是典型的模型这个具有明确时间的语义--例如从"球是平的"到"这个球是平时的时间T"。如果我们有两个相互矛盾的声明,我们有一个不一致声明的系统,虽然这可能是解决通过引入 柔软的 限制(优先事项,概率,等)。 或利用paraconsistent逻辑。

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

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

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

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

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

我会解释它如DP是一种方式来表达

  • 一个 目标表达, 的条件-什么我们正在寻找。是有一个,也许或多?
  • 一些已知的事实
  • 规则延长该知道的事实

...和那里有一个扣除通常的发动机的工作 统一 算法找到的目标。

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

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

其他几个例子说明性程序:

  • ASP.Net 标记数据绑定.它只是说,"填补这个网格,这一来源",例如,留给系统是如何出现这种情况。
  • 皇宫的表情

说明性程序是不错的,因为它可以帮助 简化你的心理模型*代码,而且因为它最终可能多个可扩展。

例如,我们说你有一个功能,做到每个元件阵列,或者名单。传统的代码这样的:

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

没什么大不了那里。但是如果您使用更多的声明的语法和替代定义或重写现有的()作为一个动作?然后你可以说它是这样的:

MyList.ForEach(DoSometing);

这当然是更简洁。但我敢肯定你有更多的关注不仅仅是挽救两条线这里的代码和存在。性能,例如。旧的方式,处理必须在顺序。如果有什么的.ForEach()方法有一个方法可以让你信号,它可以处理的处理并行的,自动?现在你突然做了你的代码多螺纹在一个很安全的方式和仅仅改变一行代码。而且,事实上,有一个 扩展 为。净,让你做到这一点。

  • 如果你跟那个链接,它需要你的博客后通过我的一个朋友。整个后是有点长,但是你可以滚动下的标题为标题 "问题"_and把它捡起来没有问题。

这取决于你如何提交答案的文本。总体而言,你可以看到的方案在一定看法,但它取决于什么角度看待问题。我会让你开始的方案:昏暗的车,汽车、时间、高度为Integr

这又取决于什么的问题是一个整体。你可能需要缩短,由于该方案。希望这可以帮助和需要的反馈意见,如果它没有。谢谢你。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top