什么是声明式编程?

发布于 2024-07-05 21:25:10 字数 36 浏览 10 评论 0原文

我不断听到这个术语在几个不同的上下文中出现。 它是什么?

I keep hearing this term tossed around in several different contexts. What is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

萌梦深 2024-07-12 21:25:10

声明式编程是指您以描述您想要做什么而不是如何做的方式编写代码。 由编译器来决定如何实现。

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

Declarative programming is when you write your code in such a way that it describes what you want to do, and not how you want to do it. It is left up to the compiler to figure out the how.

Examples of declarative programming languages are SQL and Prolog.

别再吹冷风 2024-07-12 21:25:10

其他答案已经很好地解释了声明式编程是什么,所以我将提供一些示例来说明为什么它可能有用。

上下文无关

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

yacc为例。 它又名解析器生成器。 编译器 编译器,用于描述语言语法的外部声明性 DSL,以便可以根据描述自动生成该语言的解析器。 由于其上下文独立性,您可以使用这样的语法执行许多不同的操作:

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

还有更多……

优化

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

这里有一个有趣的权衡:与命令式语言相比,机器必须更加努力地弄清楚如何做某事,但是当它确实弄清楚时出来,它在优化阶段有更多的自由和更多的信息。

The other answers already do a fantastic job explaining what declarative programming is, so I'm just going to provide some examples of why that might be useful.

Context Independence

Declarative Programs are context-independent. Because they only declare what the ultimate goal is, but not the intermediary steps to reach that goal, the same program can be used in different contexts. This is hard to do with imperative programs, because they often depend on the context (e.g. hidden state).

Take yacc as an example. It's a parser generator aka. compiler compiler, an external declarative DSL for describing the grammar of a language, so that a parser for that language can automatically be generated from the description. Because of its context independence, you can do many different things with such a grammar:

  • Generate a C parser for that grammar (the original use case for yacc)
  • Generate a C++ parser for that grammar
  • Generate a Java parser for that grammar (using Jay)
  • Generate a C# parser for that grammar (using GPPG)
  • Generate a Ruby parser for that grammar (using Racc)
  • Generate a tree visualization for that grammar (using GraphViz)
  • simply do some pretty-printing, fancy-formatting and syntax highlighting of the yacc source file itself and include it in your Reference Manual as a syntactic specification of your language

And many more …

Optimization

Because you don't prescribe the computer which steps to take and in what order, it can rearrange your program much more freely, maybe even execute some tasks in parallel. A good example is a query planner and query optimizer for a SQL database. Most SQL databases allow you to display the query that they are actually executing vs. the query that you asked them to execute. Often, those queries look nothing like each other. The query planner takes things into account that you wouldn't even have dreamed of: rotational latency of the disk platter, for example or the fact that some completely different application for a completely different user just executed a similar query and the table that you are joining with and that you worked so hard to avoid loading is already in memory anyway.

There is an interesting trade-off here: the machine has to work harder to figure out how to do something than it would in an imperative language, but when it does figure it out, it has much more freedom and much more information for the optimization stage.

你穿错了嫁妆 2024-07-12 21:25:10

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

定义

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

声明式编程的其他引用属性均源自此 RT。 请点击上面的超链接查看详细说明。

电子表格示例

两个答案提到了电子表格编程。 如果电子表格编程(又名公式)不访问可变的全局状态,则它是声明式编程。 这是因为可变单元值是 main()(整个程序)的整体输入输出。 在执行每个公式后,新值不会写入单元格,因此它们在声明性程序的生命周期内(电子表格中所有公式的执行)是不可改变的。 因此,相对于彼此,公式将这些可变单元格视为不可变的。 RT 函数可以访问不可变全局状态(以及可变本地状态)。

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

I am sorry, but I must disagree with many of the other answers. I would like to stop this muddled misunderstanding of the definition of declarative programming.

Definition

Referential transparency (RT) of the sub-expressions is the only required attribute of a declarative programming expression, because it is the only attribute which is not shared with imperative programming.

Other cited attributes of declarative programming, derive from this RT. Please click the hyperlink above for the detailed explanation.

Spreadsheet example

Two answers mentioned spreadsheet programming. In the cases where the spreadsheet programming (a.k.a. formulas) does not access mutable global state, then it is declarative programming. This is because the mutable cell values are the monolithic input and output of the main() (the entire program). The new values are not written to the cells after each formula is executed, thus they are not mutable for the life of the declarative program (execution of all the formulas in the spreadsheet). Thus relative to each other, the formulas view these mutable cells as immutable. An RT function is allowed to access immutable global state (and also mutable local state).

Thus the ability to mutate the values in the cells when the program terminates (as an output from main()), does not make them mutable stored values in the context of the rules. The key distinction is the cell values are not updated after each spreadsheet formula is performed, thus the order of performing the formulas does not matter. The cell values are updated after all the declarative formulas have been performed.

吐个泡泡 2024-07-12 21:25:10

松散地:

声明式编程倾向于:-

  • 声明集或声明性语句,每个声明或声明语句都有意义(通常在问题域中)并且可以独立且孤立地理解。

命令式编程倾向于:-

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

因此,命令式风格可以帮助读者理解系统实际执行的机制,但可能无法深入了解系统要解决的问题。 另一方面,声明式风格有助于读者理解问题领域以及系统解决问题所采取的方法,但在机制方面的信息较少。

真实的程序(即使是用偏向于极端的语言编写的程序,例如 ProLog 或 C)往往会在不同的点以不同的程度呈现两种风格,以满足作品不同的复杂性和通信需求。 一种风格并不优于另一种风格; 它们只是服务于不同的目的,就像生活中的许多事情一样,适度是关键。

Loosely:

Declarative programming tends towards:-

  • Sets of declarations, or declarative statements, each of which has meaning (often in the problem domain) and may be understood independently and in isolation.

Imperative programming tends towards:-

  • Sequences of commands, each of which perform some action; but which may or may not have meaning in the problem domain.

As a result, an imperative style helps the reader to understand the mechanics of what the system is actually doing, but may give little insight into the problem that it is intended to solve. On the other hand, a declarative style helps the reader to understand the problem domain and the approach that the system takes towards the solution of the problem, but is less informative on the matter of mechanics.

Real programs (even ones written in languages that favor the ends of the spectrum, such as ProLog or C) tend to have both styles present to various degrees at various points, to satisfy the varying complexities and communication needs of the piece. One style is not superior to the other; they just serve different purposes, and, as with many things in life, moderation is key.

回忆追雨的时光 2024-07-12 21:25:10

这是一个示例。

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

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

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

读取并解释此 CSS 的浏览器引擎可以自由地使图像看起来如此高和如此宽,无论它想要什么。 不同的浏览器引擎(例如IE的引擎、Chrome的引擎)将以不同的方式实现此任务。

当然,它们独特的实现不是用声明性语言编写的,而是用程序语言编写的,如汇编、C、C++、Java、JavaScript 或 Python。 该代码是一系列要逐步执行的步骤(可能包括函数调用)。 它可能会执行诸如插入像素值并在屏幕上渲染之类的操作。

Here's an example.

In CSS (used to style HTML pages), if you want an image element to be 100 pixels high and 100 pixels wide, you simply "declare" that that's what you want as follows:

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

You can consider CSS a declarative "style sheet" language.

The browser engine that reads and interprets this CSS is free to make the image appear this tall and this wide however it wants. Different browser engines (e.g., the engine for IE, the engine for Chrome) will implement this task differently.

Their unique implementations are, of course, NOT written in a declarative language but in a procedural one like Assembly, C, C++, Java, JavaScript, or Python. That code is a bunch of steps to be carried out step by step (and might include function calls). It might do things like interpolate pixel values, and render on the screen.

归属感 2024-07-12 21:25:10

声明式编程是使用声明(即声明性语句)进行编程。 陈述句具有许多与祈使句不同的属性。 特别是,声明是:

  • 可交换的(可以重新排序)
  • 关联的(可以重新组合)
  • 幂等的(可以重复而不改变含义) 单调
  • 的(声明不会减去信息)

相关的一点是,这些都是结构属性,并且与主题。 声明式并不是关于“什么与如何”。。 我们可以像声明“什么”一样轻松地声明(表示和约束)“如何”声明性是关于结构,而不是内容。声明性编程对我们如何抽象和重构代码以及如何将其模块化为子程序有重大影响,但对领域模型影响不大。

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

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

Declarative Programming is programming with declarations, i.e. declarative sentences. Declarative sentences have a number of properties that distinguish them from imperative sentences. In particular, declarations are:

  • commutative (can be reordered)
  • associative (can be regrouped)
  • idempotent (can repeat without change in meaning)
  • monotonic (declarations don't subtract information)

A relevant point is that these are all structural properties and are orthogonal to subject matter. Declarative is not about "What vs. How". We can declare (represent and constrain) a "how" just as easily as we declare a "what". Declarative is about structure, not content. Declarative programming has a significant impact on how we abstract and refactor our code, and how we modularize it into subprograms, but not so much on the domain model.

Often, we can convert from imperative to declarative by adding context. E.g. from "Turn left. (... wait for it ...) Turn Right." to "Bob will turn left at intersection of Foo and Bar at 11:01. Bob will turn right at the intersection of Bar and Baz at 11:06." Note that in the latter case the sentences are idempotent and commutative, whereas in the former case rearranging or repeating the sentences would severely change the meaning of the program.

Regarding monotonic, declarations can add constraints which subtract possibilities. But constraints still add information (more precisely, constraints are information). If we need time-varying declarations, it is typical to model this with explicit temporal semantics - e.g. from "the ball is flat" to "the ball is flat at time T". If we have two contradictory declarations, we have an inconsistent declarative system, though this might be resolved by introducing soft constraints (priorities, probabilities, etc.) or leveraging a paraconsistent logic.

单身情人 2024-07-12 21:25:10

声明式编程是一幅图画,而命令式编程是绘制该图画的指令。

如果您“告诉它它是什么”,那么您就是在以声明性风格编写,而不是描述计算机为到达您想要的位置而应采取的步骤。

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

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

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

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

    结构化配置文件使用声明性

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

    HTML

Declarative programming is the picture, where imperative programming is instructions for painting that picture.

You're writing in a declarative style if you're "Telling it what it is", rather than describing the steps the computer should take to get to where you want it.

When you use XML to mark-up data, you're using declarative programming because you're saying "This is a person, that is a birthday, and over there is a street address".

Some examples of where declarative and imperative programming get combined for greater effect:

  • Windows Presentation Foundation uses declarative XML syntax to describe what a user interface looks like, and what the relationships (bindings) are between controls and underlying data structures.

  • Structured configuration files use declarative syntax (as simple as "key=value" pairs) to identify what a string or value of data means.

  • HTML marks up text with tags that describe what role each piece of text has in relation to the whole document.

短暂陪伴 2024-07-12 21:25:10

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

换句话说,您不需要编写由表达式组成的算法,您只需按照您想要的方式进行布局即可。 HTML 和 WPF 是两个很好的例子。

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

It's a method of programming based around describing what something should do or be instead of describing how it should work.

In other words, you don't write algorithms made of expressions, you just layout how you want things to be. Two good examples are HTML and WPF.

This Wikipedia article is a good overview: http://en.wikipedia.org/wiki/Declarative_programming

追我者格杀勿论 2024-07-12 21:25:10

向计算机描述你想要什么,而不是如何做某事。

Describing to a computer what you want, not how to do something.

安穩 2024-07-12 21:25:10

想象一个 Excel 页面。 列中填充有计算纳税申报表的公式。

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

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

Prolog 是我使用过的唯一声明性语言。 它需要不同的思维方式,但如果只是为了让您接触典型的过程编程语言之外的东西,那么学习它是很好的。

imagine an excel page. With columns populated with formulas to calculate you tax return.

All the logic is done declared in the cells, the order of the calculation is by determine by formula itself rather than procedurally.

That is sort of what declarative programming is all about. You declare the problem space and the solution rather than the flow of the program.

Prolog is the only declarative language I've use. It requires a different kind of thinking but it's good to learn if just to expose you to something other than the typical procedural programming language.

梦在深巷 2024-07-12 21:25:10

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

我的理解(研究)的详细版本在此链接< /strong>,您应该阅读它以深入了解我将在下面提供的摘要。

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

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

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

DP 的一个更有用的定义是编程指令的排序和/或重复不会改变任何不透明的语义。 换句话说,语义中不会发生隐藏的随机变化——程序指令顺序和/或重复的任何变化只会导致程序行为的有意且透明的变化。

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

I have refined my understanding of declarative programming, since Dec 2011 when I provided an answer to this question. Here follows my current understanding.

The long version of my understanding (research) is detailed at this link, which you should read to gain a deep understanding of the summary I will provide below.

Imperative programming is where mutable state is stored and read, thus the ordering and/or duplication of program instructions can alter the behavior (semantics) of the program (and even cause a bug, i.e. unintended behavior).

In the most naive and extreme sense (which I asserted in my prior answer), declarative programming (DP) is avoiding all stored mutable state, thus the ordering and/or duplication of program instructions can NOT alter the behavior (semantics) of the program.

However, such an extreme definition would not be very useful in the real world, since nearly every program involves stored mutable state. The spreadsheet example conforms to this extreme definition of DP, because the entire program code is run to completion with one static copy of the input state, before the new states are stored. Then if any state is changed, this is repeated. But most real world programs can't be limited to such a monolithic model of state changes.

A more useful definition of DP is that the ordering and/or duplication of programming instructions do not alter any opaque semantics. In other words, there are not hidden random changes in semantics occurring-- any changes in program instruction order and/or duplication cause only intended and transparent changes to the program's behavior.

The next step would be to talk about which programming models or paradigms aid in DP, but that is not the question here.

顾北清歌寒 2024-07-12 21:25:10

自从我写下之前的答案以来,我制定了新定义下面引用的声明性属性。 我还将命令式编程定义为双重属性。

这个定义优于我在之前的回答中提供的定义,因为它简洁且更笼统。 但这可能更难理解,因为适用于编程和一般生活的不完备性定理的含义对于人类来说很难理解。

引用的定义解释讨论了纯函数式编程在声明式编程中扮演的角色。

声明式与命令式

声明性属性是奇怪的、迟钝的,并且很难在技术上精确的定义中捕获,而该定义仍然是通用且明确的,因为我们可以声明程序的含义(又名语义)而不会产生意想不到的方面,这是一个天真的想法影响。 意义的表达和避免意外影响之间存在着内在的张力,这种张力实际上源自编程和我们的宇宙的不完备性定理

将声明性定义为要做什么和命令性定义为如何做”过于简单化,技术上不精确,而且常常含糊不清。待办事项。 一个不明确的情况是,在输出程序(编译器)的程序中,“什么”是“如何”。

显然,使语言图灵完备的无界递归,也是在语义上类似——不仅仅是在评估的句法结构(又名操作语义)中。 这在逻辑上是一个类似于哥德尔定理的例子——“任何完整的公理系统也是不一致的”。 思考一下这句话的矛盾的奇怪之处! 这也是一个例子,说明语义的表达没有可证明的界限,因此我们无法证明2 程序(及其类似的语义)停止,又名停止定理。

不完备性定理源于我们宇宙的基本性质,正如热力学第二定律所述,“熵”(又名独立可能性的数量)趋向于最大值永远”。 程序的编码和设计永远不会完成——它是活的!——因为它试图满足现实世界的需求,而现实世界的语义总是在变化并趋向于更多的可能性。 人类永远不会停止发现新事物(包括程序中的错误;-)。

要在这个没有边缘的奇怪宇宙中精确地、技术性地捕捉上述所需的概念(想想看!我们的宇宙没有“外部”),需要一个简洁但看似不简单的定义,这听起来是不正确的,直到解释得很深入。

定义:

<块引用>
<小时>

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

命令式属性3是对偶,其语义在以下情况下不一致组成和/或可以用语句集的变体来表达。

<小时>

这种声明性定义在语义范围内具有明显的本地特征,这意味着它要求模块化语义保持其一致的含义,无论其在全局中的实例化和使用方式如何范围。 因此,每个声明性模块化语义本质上应该与所有可能的其他语义正交,而不是不可能的(由于定理不完整性)全局见证一致性的算法或模型,这也是“越多并不总是越好” 作者:卡内基梅隆大学计算机科学教授、标准机器学习的设计者之一 Robert Harper。

这些模块化声明语义的示例包括类别论函子,例如 应用、名义类型、名称空间、命名字段以及语义操作级别的操作级别,然后是纯函数式编程。

因此,设计良好的声明性语言可以更清晰地表达含义,尽管在​​可表达的内容方面失去了一些通用性,但在可表达的内容方面取得了内在的一致性。

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

超文本标记语言又名 HTML(静态网页语言)是高度(但并不完美)的示例3) 声明性语言(至少在 HTML 5 之前)无法表达动态行为。 HTML 或许是最容易学习的语言。 对于动态行为,命令式脚本语言(例如 JavaScript)通常与 HTML 结合使用。 没有 JavaScript 的 HTML 适合声明性定义,因为每个名义类型(即标签)在语法规则内的组合下保持其一致的含义。

声明性的一个相互竞争的定义是可交换性语义语句的幂等属性,即语句可以重新排序和复制而不改变含义。 例如,如果这些名称对于任何隐含顺序都是模块化的,则可以对命名字段赋值的语句进行重新排序和复制,而不会更改程序的含义。 名称有时暗示顺序,例如单元格标识符包括它们的列和行位置——在电子表格上移动总计会改变其含义。 否则,这些属性隐含地要求语义的全局一致性。 通常不可能设计语句的语义,使它们在随机排序或重复时保持一致,因为顺序和重复是语义所固有的。 例如,陈述“Foo存在”(或构造)和“Foo不存在”(和破坏)。 如果人们认为随机不一致是预期语义的特有现象,那么人们就会认为这一定义对于声明性属性来说足够通用。 本质上,这个定义作为一个广义的定义是空洞的,因为它试图使一致性与语义正交,即违背语义宇宙是动态无界的并且不能在全局连贯性中捕获的事实范例。

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

C、Java、C++、C#、PHP 和 JavaScript 并不是特别声明性的。
Copute 的语法和 Python 的语法更加声明性耦合到
预期结果
,即一致的句法语义,消除无关的内容,以便人们可以轻松地
在他们忘记代码后理解它。 Copute 和 Haskell 强制执行
操作语义的确定性并鼓励“不要重复
你自己
”(DRY),因为它们只允许纯函数范式。

<小时>

2 即使我们可以证明以下语义程序,例如 Coq 语言,这仅限于 打字,打字永远无法捕获程序的所有语义——即使对于非图灵完备的语言也是如此,例如使用HTML+CSS,可以表达不一致的组合,从而具有未定义的语义。< /p>

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


编辑:我发布了 以下评论到罗伯特·哈珀的博客:

<块引用>

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

取决于人们如何区分函数式和命令式
编程时,命令式程序中的“可分配”也可能有
对其可变性施加限制的类型。

我目前唯一欣赏的函数式定义
编程是 a) 作为第一类对象和类型的函数,b)
优先选择递归而不是循环,和/或 c) 纯函数——即
那些不影响所需语义的函数
记忆时的程序(因此完全纯函数
编程不存在于通用的指称语义中
由于操作语义的影响,例如内存
分配
)。

纯函数的幂等性意味着函数调用
它的变量可以用它的值来代替,这通常不是
强制程序论证的情况。 纯函数
对于未组合的状态转换似乎是声明性的
输入和结果类型之间。

但是纯函数的组合不维护任何这样的
一致性,因为可以模拟副作用(全局
状态)纯函数式编程语言中的命令式过程,
例如 Haskell 的 IOMonad 而且这是完全不可能的
防止在任何图灵完备的纯函数编程中这样做
语言。

正如我在 2012 年写道似乎有类似的共识
您最近的博客,声明式编程是
试图捕捉这样一个概念:预期的语义永远不会
不透明。 不透明语义的例子是对顺序的依赖,
依赖于操作中高层语义的擦除
语义层(例如
强制转换不是转换和具体化泛型
限制更高级别的语义
),以及对变量值的依赖
编程语言无法检查(证明正确)。

因此我得出的结论是,只有非图灵完备的语言才可以
声明式。

因此,声明性语言有一个明确且独特的属性
可能是它的输出可以被证明服从一些可枚举的集合
生成规则。 例如,对于任何特定的 HTML 程序(忽略
解释者分歧方式的差异),这是非脚本化的
(即不是图灵完整的)那么它的输出可变性可以是
可数。 或者更简洁地说,HTML 程序是以下函数的纯函数
它的可变性。 同上,电子表格程序是其纯函数
输入变量。

所以在我看来,声明性语言是以下的对立面:
无界递归,即根据哥德尔第二不完备性
定理 自指定理无法被证明。

Lesie Lamport 写了一个童话故事关于欧几里得如何可能
围绕哥德尔不完备性定理应用于数学证明
在编程语言上下文中,通过类型和之间的一致性
逻辑(库里-霍华德对应等)。

Since I wrote my prior answer, I have formulated a new definition of the declarative property which is quoted below. I have also defined imperative programming as the dual property.

This definition is superior to the one I provided in my prior answer, because it is succinct and it is more general. But it may be more difficult to grok, because the implication of the incompleteness theorems applicable to programming and life in general are difficult for humans to wrap their mind around.

The quoted explanation of the definition discusses the role pure functional programming plays in declarative programming.

Declarative vs. Imperative

The declarative property is weird, obtuse, and difficult to capture in a technically precise definition that remains general and not ambiguous, because it is a naive notion that we can declare the meaning (a.k.a semantics) of the program without incurring unintended side effects. There is an inherent tension between expression of meaning and avoidance of unintended effects, and this tension actually derives from the incompleteness theorems of programming and our universe.

It is oversimplification, technically imprecise, and often ambiguous to define declarative as what to do and imperative as how to do. An ambiguous case is the “what” is the “how” in a program that outputs a program— a compiler.

Evidently the unbounded recursion that makes a language Turing complete, is also analogously in the semantics— not only in the syntactical structure of evaluation (a.k.a. operational semantics). This is logically an example analogous to Gödel's theorem— “any complete system of axioms is also inconsistent”. Ponder the contradictory weirdness of that quote! It is also an example that demonstrates how the expression of semantics does not have a provable bound, thus we can't prove2 that a program (and analogously its semantics) halt a.k.a. the Halting theorem.

The incompleteness theorems derive from the fundamental nature of our universe, which as stated in the Second Law of Thermodynamics is “the entropy (a.k.a. the # of independent possibilities) is trending to maximum forever”. The coding and design of a program is never finished— it's alive!— because it attempts to address a real world need, and the semantics of the real world are always changing and trending to more possibilities. Humans never stop discovering new things (including errors in programs ;-).

To precisely and technically capture this aforementioned desired notion within this weird universe that has no edge (ponder that! there is no “outside” of our universe), requires a terse but deceptively-not-simple definition which will sound incorrect until it is explained deeply.

Definition:


The declarative property is where there can exist only one possible set of statements that can express each specific modular semantic.

The imperative property3 is the dual, where semantics are inconsistent under composition and/or can be expressed with variations of sets of statements.


This definition of declarative is distinctively local in semantic scope, meaning that it requires that a modular semantic maintain its consistent meaning regardless where and how it's instantiated and employed in global scope. Thus each declarative modular semantic should be intrinsically orthogonal to all possible others— and not an impossible (due to incompleteness theorems) global algorithm or model for witnessing consistency, which is also the point of “More Is Not Always Better” by Robert Harper, Professor of Computer Science at Carnegie Mellon University, one of the designers of Standard ML.

Examples of these modular declarative semantics include category theory functors e.g. the Applicative, nominal typing, namespaces, named fields, and w.r.t. to operational level of semantics then pure functional programming.

Thus well designed declarative languages can more clearly express meaning, albeit with some loss of generality in what can be expressed, yet a gain in what can be expressed with intrinsic consistency.

An example of the aforementioned definition is the set of formulas in the cells of a spreadsheet program— which are not expected to give the same meaning when moved to different column and row cells, i.e. cell identifiers changed. The cell identifiers are part of and not superfluous to the intended meaning. So each spreadsheet result is unique w.r.t. to the cell identifiers in a set of formulas. The consistent modular semantic in this case is use of cell identifiers as the input and output of pure functions for cells formulas (see below).

Hyper Text Markup Language a.k.a. HTML— the language for static web pages— is an example of a highly (but not perfectly3) declarative language that (at least before HTML 5) had no capability to express dynamic behavior. HTML is perhaps the easiest language to learn. For dynamic behavior, an imperative scripting language such as JavaScript was usually combined with HTML. HTML without JavaScript fits the declarative definition because each nominal type (i.e. the tags) maintains its consistent meaning under composition within the rules of the syntax.

A competing definition for declarative is the commutative and idempotent properties of the semantic statements, i.e. that statements can be reordered and duplicated without changing the meaning. For example, statements assigning values to named fields can be reordered and duplicated without changed the meaning of the program, if those names are modular w.r.t. to any implied order. Names sometimes imply an order, e.g. cell identifiers include their column and row position— moving a total on spreadsheet changes its meaning. Otherwise, these properties implicitly require global consistency of semantics. It is generally impossible to design the semantics of statements so they remain consistent if randomly ordered or duplicated, because order and duplication are intrinsic to semantics. For example, the statements “Foo exists” (or construction) and “Foo does not exist” (and destruction). If one considers random inconsistency endemical of the intended semantics, then one accepts this definition as general enough for the declarative property. In essence this definition is vacuous as a generalized definition because it attempts to make consistency orthogonal to semantics, i.e. to defy the fact that the universe of semantics is dynamically unbounded and can't be captured in a global coherence paradigm.

Requiring the commutative and idempotent properties for the (structural evaluation order of the) lower-level operational semantics converts operational semantics to a declarative localized modular semantic, e.g. pure functional programming (including recursion instead of imperative loops). Then the operational order of the implementation details do not impact (i.e. spread globally into) the consistency of the higher-level semantics. For example, the order of evaluation of (and theoretically also the duplication of) the spreadsheet formulas doesn't matter because the outputs are not copied to the inputs until after all outputs have been computed, i.e. analogous to pure functions.

C, Java, C++, C#, PHP, and JavaScript aren't particularly declarative.
Copute's syntax and Python's syntax are more declaratively coupled to
intended results
, i.e. consistent syntactical semantics that eliminate the extraneous so one can readily
comprehend code after they've forgotten it. Copute and Haskell enforce
determinism of the operational semantics and encourage “don't repeat
yourself
” (DRY), because they only allow the pure functional paradigm.


2 Even where we can prove the semantics of a program, e.g. with the language Coq, this is limited to the semantics that are expressed in the typing, and typing can never capture all of the semantics of a program— not even for languages that are not Turing complete, e.g. with HTML+CSS it is possible to express inconsistent combinations which thus have undefined semantics.

3 Many explanations incorrectly claim that only imperative programming has syntactically ordered statements. I clarified this confusion between imperative and functional programming. For example, the order of HTML statements does not reduce the consistency of their meaning.


Edit: I posted the following comment to Robert Harper's blog:

in functional programming ... the range of variation of a variable is a type

Depending on how one distinguishes functional from imperative
programming, your ‘assignable’ in an imperative program also may have
a type placing a bound on its variability.

The only non-muddled definition I currently appreciate for functional
programming is a) functions as first-class objects and types, b)
preference for recursion over loops, and/or c) pure functions— i.e.
those functions which do not impact the desired semantics of the
program when memoized (thus perfectly pure functional
programming doesn't exist in a general purpose denotational semantics
due to impacts of operational semantics, e.g. memory
allocation
).

The idempotent property of a pure function means the function call on
its variables can be substituted by its value, which is not generally
the case for the arguments of an imperative procedure. Pure functions
seem to be declarative w.r.t. to the uncomposed state transitions
between the input and result types.

But the composition of pure functions does not maintain any such
consistency, because it is possible to model a side-effect (global
state) imperative process in a pure functional programming language,
e.g. Haskell's IOMonad and moreover it is entirely impossible to
prevent doing such in any Turing complete pure functional programming
language.

As I wrote in 2012 which seems to the similar consensus of
comments in your recent blog, that declarative programming is an
attempt to capture the notion that the intended semantics are never
opaque. Examples of opaque semantics are dependence on order,
dependence on erasure of higher-level semantics at the operational
semantics layer (e.g. casts are not conversions and reified generics
limit higher-level semantics
), and dependence on variable values
which can not be checked (proved correct) by the programming language.

Thus I have concluded that only non-Turing complete languages can be
declarative.

Thus one unambiguous and distinct attribute of a declarative language
could be that its output can be proven to obey some enumerable set of
generative rules. For example, for any specific HTML program (ignoring
differences in the ways interpreters diverge) that is not scripted
(i.e. is not Turing complete) then its output variability can be
enumerable. Or more succinctly an HTML program is a pure function of
its variability. Ditto a spreadsheet program is a pure function of its
input variables.

So it seems to me that declarative languages are the antithesis of
unbounded recursion, i.e. per Gödel's second incompleteness
theorem self-referential theorems can't be proven.

Lesie Lamport wrote a fairytale about how Euclid might have
worked around Gödel's incompleteness theorems applied to math proofs
in the programming language context by to congruence between types and
logic (Curry-Howard correspondence, etc).

噩梦成真你也成魔 2024-07-12 21:25:10

声明式编程的其他几个示例:

  • 用于数据绑定的 ASP.Net 标记。 例如,它只是说“用这个源填充这个网格”,并将其留给系统来决定如何发生。
  • Linq 表达式

声明式编程很好,因为它可以帮助简化您的代码思维模型*,因为它最终可能更具可扩展性。

例如,假设您有一个函数对数组或列表中的每个元素执行某些操作。 传统的代码看起来像这样:

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

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

MyList.ForEach(DoSometing);

这样当然更简洁了。 但我确信您关心的不仅仅是到处保存两行代码。 例如,性能。 旧方法必须按顺序进行处理。 如果 .ForEach() 方法有一种方法可以让您发出信号表明它可以自动并行处理,该怎么办? 现在突然之间,您已经以一种非常安全的方式使代码成为多线程的,并且只更改了一行代码。 事实上,有一个

  • 如果您点击该链接,您将看到我的一个朋友的博客文章。 整篇文章有点长,但您可以向下滚动到标题为“问题”的标题,然后毫无问题地拿起它。*

A couple other examples of declarative programming:

  • ASP.Net markup for databinding. It just says "fill this grid with this source", for example, and leaves it to the system for how that happens.
  • Linq expressions

Declarative programming is nice because it can help simplify your mental model* of code, and because it might eventually be more scalable.

For example, let's say you have a function that does something to each element in an array or list. Traditional code would look like this:

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

No big deal there. But what if you use the more-declarative syntax and instead define DoSomething() as an Action? Then you can say it this way:

MyList.ForEach(DoSometing);

This is, of course, more concise. But I'm sure you have more concerns than just saving two lines of code here and there. Performance, for example. The old way, processing had to be done in sequence. What if the .ForEach() method had a way for you to signal that it could handle the processing in parallel, automatically? Now all of a sudden you've made your code multi-threaded in a very safe way and only changed one line of code. And, in fact, there's a an extension for .Net that lets you do just that.

  • If you follow that link, it takes you to a blog post by a friend of mine. The whole post is a little long, but you can scroll down to the heading titled "The Problem" _and pick it up there no problem.*
奶气 2024-07-12 21:25:10

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

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

As far as I can tell, it started being used to describe programming systems like Prolog, because prolog is (supposedly) about declaring things in an abstract way.

It increasingly means very little, as it has the definition given by the users above. It should be clear that there is a gulf between the declarative programming of Haskell, as against the declarative programming of HTML.

家住魔仙堡 2024-07-12 21:25:10

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

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

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

这两种方法之间的区别在于声明式程序
创建了一种更贴近人们心理模型的新语言
问题在于它的宿主语言。

Declarative programming is "the act of programming in languages that conform to the mental model of the developer rather than the operational model of the machine".

The difference between declarative and imperative programming is well
illustrated by the problem of parsing structured data.

An imperative program would use mutually recursive functions to consume input
and generate data. A declarative program would express a grammar that defines
the structure of the data so that it can then be parsed.

The difference between these two approaches is that the declarative program
creates a new language that is more closely mapped to the mental model of the
problem than is its host language.

如此安好 2024-07-12 21:25:10

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

It may sound odd, but I'd add Excel (or any spreadsheet really) to the list of declarative systems. A good example of this is given here.

单挑你×的.吻 2024-07-12 21:25:10

我将其解释为 DP 是表达

  • “目标表达式”的一种方式,即我们正在寻找的条件。 有一个、也许还是多个?
  • 一些已知事实
  • 扩展已知事实的规则

......以及通常使用统一算法来查找目标的演绎引擎。

I'd explain it as DP is a way to express

  • A goal expression, the conditions for - what we are searching for. Is there one, maybe or many?
  • Some known facts
  • Rules that extend the know facts

...and where there is a deduct engine usually working with a unification algorithm to find the goals.

两相知 2024-07-12 21:25:10

这取决于您如何提交文本答案。 总的来说,你可以从某个角度来看待这个程序,但这取决于你看问题的角度。 我将带您开始该计划:
Dim Bus、Car、Time、Height As Integr

同样,这取决于问题的整体情况。 由于节目原因,您可能必须缩短它。 希望这有帮助,如果没有,需要反馈。
谢谢。

It depends on how you submit the answer to the text. Overall you can look at the programme at a certain view but it depends what angle you look at the problem. I will get you started with the programme:
Dim Bus, Car, Time, Height As Integr

Again it depends on what the problem is an overall. You might have to shorten it due to the programme. Hope this helps and need the feedback if it does not.
Thank You.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文