我一直在网上搜索声明式编程和命令式编程的定义,希望能给我一些启发。然而,我发现在一些资源中使用的语言令人生畏——例如在维基百科。 有没有人可以给我举一个现实世界的例子,让我对这个主题有一些了解(也许是c#)?


当前回答

再举一个手机应用开发的例子。在iOS和Android中,我们有界面构建器,在那里我们可以定义应用程序的UI。

使用这些生成器绘制的UI本质上是声明性的,我们可以在其中拖放组件。实际的绘图发生在框架和系统下面,由框架和系统执行。

但我们也可以在代码中画出整个组件,这在本质上是必要的。

此外,一些新语言,如Angular JS,专注于以声明方式设计ui,我们可能会看到许多其他语言提供同样的支持。就像Java在Java swing或Java FX中没有任何好的声明性方法来绘制本地桌面应用程序,但在不久的将来,他们可能会这样做。

其他回答

这种差异主要与抽象的总体水平有关。对于声明式,在某些情况下,您离单个步骤太远了,以至于程序在如何获得结果方面有很大的自由度。


你可以把每一条指令都看作是连续体上的某个地方:

抽象程度:

Declarative <<=====|==================>> Imperative

声明性真实世界的例子:

图书管理员,请帮我借一本《白鲸记》。 (图书管理员可酌情选择最佳的申请方式)

现实世界的例子:

进入图书馆 查找图书组织系统(卡片目录-老派) 研究如何使用卡片目录(你也忘了,对吧) 弄清楚货架是如何标记和组织的。 弄清楚书架上的书是如何排列的。 从卡片目录和组织系统中交叉引用图书位置以查找所述书籍。 带书到退房系统。 借书。

声明性编程是你说你想要什么,命令式编程是你说如何得到你想要的。

一个简单的Python例子:

# Declarative
small_nums = [x for x in range(20) if x < 5]

# Imperative
small_nums = []
for i in range(20):
    if i < 5:
        small_nums.append(i)

第一个例子是声明性的,因为我们没有指定构建列表的任何“实现细节”。

以c#为例,一般来说,使用LINQ的结果是声明式的,因为你没有说如何获得你想要的东西;你只是在说你想说的话。你可以对SQL说同样的话。

声明式编程的一个好处是,它允许编译器做出可能比手工编写更好的代码的决定。运行SQL示例,如果您有这样的查询

SELECT score FROM games WHERE id < 100;

SQL“编译器”可以“优化”这个查询,因为它知道id是一个索引字段——或者它可能没有索引,在这种情况下,它必须遍历整个数据集。或者SQL引擎知道这是利用所有8个核心进行快速并行搜索的最佳时机。作为程序员,你不需要考虑这些条件,也不需要编写代码来处理任何特殊情况。

这里和其他在线帖子的答案提到了以下内容:

使用声明式编程,您编写的代码描述您想要的东西,但不一定是如何得到它 您应该更喜欢声明式编程而不是命令式编程

他们没有告诉我们如何实现这一目标。为了使部分程序更具声明性,其他部分必须提供抽象来隐藏实现细节(即命令式代码)。

例如,LINQ比循环(for, while等)更具声明性,例如,你可以使用list. where()来获得一个新的过滤列表。为了实现这一点,微软已经完成了LINQ抽象背后的所有繁重工作。

事实上,函数式编程和函数式库更具有声明性的原因之一是因为它们抽象了循环和列表创建,隐藏了所有实现细节(很可能是带有循环的命令式代码)。

在任何程序中,都将同时拥有命令式代码和声明式代码,并且应该将所有命令式代码隐藏在特定于领域的抽象后面,以便程序的其他部分可以声明性地使用它们。

最后,尽管函数式编程和LINQ可以使您的程序更具声明性,但您总是可以通过提供更多的抽象来使程序更具声明性。例如:

// JavaScript example

// Least declarative
const bestProducts = [];
for(let i = 0; i < products.length; i++) {
    let product = products[i];
    if (product.rating >= 5 && product.price < 100) {
        bestProducts.push(product);
    }
}


// More declarative
const bestProducts = products.filter(function(product) {
    return product.rating >= 5 && product.price < 100;
});

// Most declarative, implementation details are hidden in a function
const bestProducts = getBestProducts();

另外,声明式编程的极端是发明新的领域特定语言(DSL):

字符串搜索:正则表达式而不是自定义命令式代码 js: JSX而不是直接的DOM操作 AWS CloudFormation:用YAML代替CLI 关系型数据库:用SQL代替旧的读写api,如ISAM或VSAM。

再举一个手机应用开发的例子。在iOS和Android中,我们有界面构建器,在那里我们可以定义应用程序的UI。

使用这些生成器绘制的UI本质上是声明性的,我们可以在其中拖放组件。实际的绘图发生在框架和系统下面,由框架和系统执行。

但我们也可以在代码中画出整个组件,这在本质上是必要的。

此外,一些新语言,如Angular JS,专注于以声明方式设计ui,我们可能会看到许多其他语言提供同样的支持。就像Java在Java swing或Java FX中没有任何好的声明性方法来绘制本地桌面应用程序,但在不久的将来,他们可能会这样做。

已经添加了很多代码示例,所以我不再添加另一个。 相反,我将尝试用一种我认为比大多数流行的定义更清楚地解释这两种方法之间的区别:

声明性方法侧重于特定算法的目的,这通常隐藏了算法本身。 命令式方法侧重于特定目的的算法,通常隐藏了目的本身。