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


当前回答

声明性程序只是它的一些或多或少的“通用”命令式实现/虚拟机的数据。

pluses: specifying just a data, in some hardcoded (and checked) format, is simpler and less error-prone than specifying variant of some imperative algorithm directly. some complex specifications just cant be written directly, only in some DSL form. best and freq used in DSLs data structures is sets and tables. because you not have dependencies between elements/rows. and when you havent dependencies you have freedom to modify and ease of support. (compare for example modules with classes - with modules you happy and with classes you have fragile base class problem) all goods of declarativeness and DSL follows immediately from benefits of that data structures (tables and sets). another plus - you can change implementation of declarative language vm, if DSL is more-or-less abstract (well designed). make parallel implementation, for example. or port it to other os etc. all good specifed modular isolating interfaces or protocols gives you such freedom and easyness of support.

缺点: 你猜对了。一般的(通过DSL参数化的)命令式算法/虚拟机实现可能比特定的算法慢和/或占用内存。在某些情况下。 如果这种情况很罕见,那就忘了它吧,让它慢慢来。如果这种情况经常发生,你总是可以扩展你的DSL/vm。某个能减缓其他案件的地方,当然…

P.S.框架介于DSL和命令式之间。作为所有的折中方案……他们结合了缺点,而不是优点。它们不是那么安全,也不是那么快:)看看万事通haskell——它介于强大的简单ML和灵活的元程序Prolog之间……真是个怪物。你可以把Prolog看作一个Haskell,它只包含布尔函数/谓词。它对Haskell的灵活性是多么简单……

其他回答

命令式编程是显式地告诉计算机做什么,以及如何做,比如指定顺序等

C#:

for (int i = 0; i < 10; i++)
{
    System.Console.WriteLine("Hello World!");
}

说明性是指你告诉计算机做什么,而不是如何做。Datalog / Prolog是在这方面首先想到的语言。基本上所有东西都是声明性的。你不能保证秩序。

c#是一种更命令式的编程语言,但某些c#特性更具有声明性,如Linq

dynamic foo = from c in someCollection
           let x = someValue * 2
           where c.SomeProperty < x
           select new {c.SomeProperty, c.OtherProperty};

同样的东西也可以写成命令式:

dynamic foo = SomeCollection.Where
     (
          c => c.SomeProperty < (SomeValue * 2)
     )
     .Select
     (
          c => new {c.SomeProperty, c.OtherProperty}
     )

(例子来自维基百科Linq)

这里借用菲利普·罗伯茨的一句话:

命令式编程告诉机器如何做某事(导致你想要发生的事情) 声明性编程告诉机器你想要发生什么(然后计算机找出如何去做)

两个例子:

1. 将数组中的所有数字加倍

命令式地:

var numbers = [1,2,3,4,5]
var doubled = []

for(var i = 0; i < numbers.length; i++) {
  var newNumber = numbers[i] * 2
  doubled.push(newNumber)
}
console.log(doubled) //=> [2,4,6,8,10]

声明:

var numbers = [1,2,3,4,5]

var doubled = numbers.map(function(n) {
  return n * 2
})
console.log(doubled) //=> [2,4,6,8,10]

2. 对列表中的所有项求和

命令式地

var numbers = [1,2,3,4,5]
var total = 0

for(var i = 0; i < numbers.length; i++) {
  total += numbers[i]
}
console.log(total) //=> 15

以声明的方式

var numbers = [1,2,3,4,5]

var total = numbers.reduce(function(sum, n) {
  return sum + n
});
console.log(total) //=> 15

请注意,命令式示例涉及如何创建一个新变量,改变它,并返回新值(即,如何使某事发生),而声明式示例执行给定的输入,并根据初始输入返回新值(即,我们想要发生什么)。

我喜欢剑桥一门课程的解释和他们的例子:

声明性-指定要做什么,而不是如何做 例如:HTML描述的是什么应该出现在网页上,而不是它应该如何在屏幕上绘制 命令式-同时指定“什么”和“如何” int x;-什么(陈述性的) x = x + 1;——如何

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

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

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

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

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

例如,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。