声明式编程与命令式编程

先统一一下概念,我们有两种编程方式:命令式和声明式。

我们可以像下面这样定义它们之间的不同:

·命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
·声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

声明式编程和命令式编程的代码例子:

  举个简单的例子,假设我们想让一个数组里的数值翻倍。

  我们用命令式编程风格实现,像下面这样:

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]

  我们直接遍历整个数组,取出每个元素,乘以二,然后把翻倍后的值放入新数组,每次都要操作这个双倍数组,直到计算完所有元素。

  而使用声明式编程方法,我们可以用 Array.map 函数,像下面这样:

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

var doubled = numbers.map(function(n) {

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

  map 利用当前的数组创建了一个新数组,新数组里的每个元素都是经过了传入map的函数(这里是function(n) { return n*2 })的处理。

  map函数所作的事情是将直接遍历整个数组的过程归纳抽离出来,让我们专注于描述我们想要的是什么(what)。注意,我们传入map的是一个纯函数;它不具有任何副作用(不会改变外部状态),它只是接收一个数字,返回乘以二后的值。

  在一些具有函数式编程特征的语言里,对于list数据类型的操作,还有一些其他常用的声明式的函数方法。例如,求一个list里所有值的和,命令式编程会这样做:

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

  而在声明式编程方式里,我们使用 reduce 函数:

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

var total = numbers.reduce(function(sum, n) {

  return sum + n
});
console.log(total) //=> 15

  reduce 函数利用传入的函数把一个 list 运算成一个值。它以这个函数为参数,数组里的每个元素都要经过它的处理。每一次调用,第一个参数(这里是sum)都是这个函数处理前一个值时返回的结果,而第二个参数(n)就是当前元素。这样下来,每此处理的新元素都会合计到sum中,最终我们得到的是整个数组的和。

  同样,reduce 函数归纳抽离了我们如何遍历数组和状态管理部分的实现,提供给我们一个通用的方式来把一个 list 合并成一个值。我们需要做的只是指明我们想要的是什么?

声明式编程很奇怪吗?

  如果你之前没有听说过map 和 reduce 函数,你的第一感觉,我相信,就会是这样。作为程序员,我们非常习惯去指出事情应该如何运行。“去遍历这个list”,“if 这种情况 then 那样做”,“把这个新值赋给这个变量”。当我们已经知道了如何告诉机器该如何做事时,为什么我们需要去学习这种看起来有些怪异的归纳抽离出来的函数工具?

  在很多情况中,命令式编程很好用。当我们写业务逻辑,我们通常必须要写命令式代码,没有可能在我们的专项业务里也存在一个可以归纳抽离的实现。

  但是,如果我们花时间去学习(或发现)声明式的可以归纳抽离的部分,它们能为我们的编程带来巨大的便捷。首先,我可以少写代码,这就是通往成功的捷径。而且它们能让我们站在更高的层面是思考,站在云端思考我们想要的是什么,而不是站在泥里思考事情该如何去做。

声明式编程语言:SQL

  也许你还不能明白,但有一个地方,你也许已经用到了声明式编程,那就是SQL。

  你可以把SQL当做一个处理数据的声明式查询语言。完全用SQL写一个应用程序?这不可能。但如果是处理相互关联的数据集,它就显的无比强大了。

  像下面这样的查询语句:

SELECT * from dogs
INNER JOIN owners

WHERE dogs.owner_id = owners.id

  如果我们用命令式编程方式实现这段逻辑:

//dogs = [{name: ‘Fido‘, owner_id: 1}, {...}, ... ]
//owners = [{id: 1, name: ‘Bob‘}, {...}, ...]

var dogsWithOwners = []
var dog, owner

for(var di=0; di < dogs.length; di++) {

  dog = dogs[di]

  for(var oi=0; oi < owners.length; oi++) {

    owner = owners[oi]
    if (owner && dog.owner_id == owner.id) {

      dogsWithOwners.push({
        dog: dog,
        owner: owner

      })
    }
  }}
}

  我可没说SQL是一种很容易懂的语言,也没说一眼就能把它们看明白,但基本上还是很整洁的。

  SQL代码不仅很短,不不仅容易读懂,它还有更大的优势。因为我们归纳抽离了how,我们就可以专注于what,让数据库来帮我们优化how.

  我们的命令式编程代码会运行的很慢,因为需要遍历所有 list 里的每个狗的主人。

  而SQL例子里我们可以让数据库来处理how,来替我们去找我们想要的数据。如果需要用到索引(假设我们建了索引),数据库知道如何使用索引,

这样性能又有了大的提升。如果在此不久之前它执行过相同的查询,它也许会从缓存里立即找到。通过放手how,让机器来做这些有难度的事,我们不

需要掌握数据库原理就能轻松的完成任务。

声明式编程:d3.js

  另外一个能体现出声明式编程的真正强大之处地方是用户界面、图形、动画编程。

  开发用户界面是有难度的事。因为有用户交互,我们希望能创建漂亮的动态用户交互方式,通常我们会用到大量的状态声明和很多相同作用的代

码,这些代码实际上是可以归纳提炼出来的。

  d3.js 里面一个非常好的声明时归纳提炼的例子就是它的一个工具包,能够帮助我们使用JavaScript和SVG来开发交互的和动画的数据可视化模型。

  第一次(或第5次,甚至第10次)你开发d3程序时可能会头大。跟SQL一样,d3是一种可视化数据操作的强大通用工具,它能提供你所有how方法,让你只需要说出你想要什么。

  下面是一个例子(我建议你看一下这个演示)。这是一个d3可视化实现,它为data数组里的每个对象画一个圆。为了演示这个过程,我们每秒增加一个圆。

  里面最有趣的一段代码是:

//var data = [{x: 5, y: 10}, {x: 20, y: 5}]

var circles = svg.selectAll(‘circle‘)

                    .data(data)

circles.enter().append(‘circle‘)

           .attr(‘cx‘, function(d) { return d.x })

           .attr(‘cy‘, function(d) { return d.y })

           .attr(‘r‘, 0)
        .transition().duration(500)

          .attr(‘r‘, 5)

  没有必要完全理解这段代码都干了什么(你需要一段时间去领会),但关键点是:

  首先我们收集了svg里所有的圆,然后把data数组数据绑定到对象里。

  D3 对每个圆都绑定了那些点数据有一个关系表。最初我们只有两个点,没有圆,我们使用.enter()方法获取数据点。这里,我们的意图是画一个圆,中心是x 和 y,初始值是 0 ,半秒后变换成半径为 5。

  命令式编程就是对硬件操作的抽象, 程序员需要通过指令,精确的告诉计算机干什么事情。

  声明性是函数式编程的一个重要特点, 函数式还有其他特点, 像高阶函数、函数没有side effect, 只有值而没有变量, 用递归而不是用迭代等等。 想

  要完全的掌握函数式需要你彻底的刷新思维, 甚至忘掉命令式的习惯, 所以学习曲线比较陡峭。

  但是这并不妨碍“声明性”这个特点在某些特定领域的应用, 因为它的确能极大的简化代码。

参考:

http://www.vaikan.com/

http://mp.weixin.qq.com/s/n_b-yUIxf9ohnYa3Iefoig

时间: 2024-10-25 20:14:04

声明式编程与命令式编程的相关文章

命令式编程vs声明式编程

英文原文:Imperative vs Declarative 先统一一下概念,我们有两种编程方式:命令式和声明式. 我们可以像下面这样定义它们之间的不同: 命令式编程:命令"机器"如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现. 声明式编程:告诉"机器"你想要的是什么(what),让机器想出如何去做(how). 声明式编程和命令式编程的代码例子举个简单的例子,假设我们想让一个数组里的数值翻倍. 1.我们用命令式编程风格实现,像下面

编程范式:命令式编程(Imperative)、声明式编程(Declarative)和函数式编程(Functional)

主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 命令式编程:命令式编程的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么.比如:如果你想在一个数字集合 collection(变量名) 中筛选大于 5 的数字,你需要这样告诉计算机:第一步,创建一个存储结果的集合变量 results:第二步,遍历这个数字集合 collection:第三步:一个一个地判断每个数字是不是大于 5,如果是就将这个数字添加到结果集合变量 results 中.代码实现如下: List<int>

函数式编程 vs 命令式编程

函数式编程 vs 命令式编程 函数式编程属于声明式编程(Declarative Programming),SQL就是典型的声明式编程. 函数式编程(Functional Programming) 关注行为 强调what,对应于数学里面的函数的对应法则. 像餐馆里吃饭,提出自己的要求即可 数学函数概念含有三个要素:定义域A.值域C和对应法则f.其中核心是对应法则f,它是函数关系的本质特征. 命令式编程(Imperative Programming) 关注数据 强调how,每一步都需要去做 像在家里

函数式编程和命令式编程

所谓命令式编程,是以命令为主的,给机器提供一条又一条的命令序列让其原封不动的执行.程序执行的效率取决于执行命令的数量.因此才会出现大O表示法等等表示时间空间复杂度的符号. 而函数式语言并不是通常意义上理解的“通过函数的变换进行编程”.注意到纯的函数式语言中是没有变量的(没有可以改变的东西,所有的东西在定义以后就都是不变的),那么这样的东西有什么好处呢?就比如,如果所有的东西都是不变的,那么我们又怎么进行编程呢? 实际上,我们在函数式编程中进行构建的是实体与实体之间的关系.在这种意义上,lisp虽

Atitit 函数式编程与命令式编程的区别attilax总结 &#160;qbf

Atitit 函数式编程与命令式编程的区别attilax总结  qbf 1.1. 函数式程序就是一个表达式.命令式程序就是一个冯诺依曼机的指令序列. 命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取,存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),一句话,命令式程序就是一个冯诺依曼机的指令序列. 而函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式. 1.2. 面向对象语言中,数据类型分为两种--基本类型和对象类型(

Python - 命令式编程与符号编程

原文链接:https://zh.d2l.ai/chapter_computational-performance/hybridize.html本文是对原文内容的摘取和扩展. 命令式编程(imperative style programs) 使用编程语句改变程序状态,明确输入变量,并根据程序逻辑逐步运算. 易于理解:在Python里使用命令式编程时,大部分代码编写起来都很直观. 容易调试:可以很方便地进行单步跟踪,获取并分析所有中间变量,或者使用Python的调试工具. 虽然使用命令式编程很方便,

Unity基于响应式编程(Reactive programming)入门

系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现 时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率 背景 前有慕容小匹夫的一篇<解构C#游戏框架uFrame兼谈游戏架构设计&

看武侠学编程_以九宫格为例介绍强大的声明式语言Prolog

如果要给众多编程语言分个类,你可能会把它们分成低级语言和高级语言,或者分成面向对象语言和面向过程语言.然而,更多中国程序员所不太熟悉的另外一种划分方式将会把计算机语言分成命令式和声明式两大阵营.之所以说大家可能不太熟悉这种划分,那是因为我们平常所使用绝大部分语言都是命令式的.但事实上你确实也应该注意到另外一大阵营的存在. 命令式编程(ImperativeProgramming)是现今最为广泛使用的编程范型.读者所熟知的众多计算机语言,如C.C++.Java.Pascal.Basic.Python

面向函数范式编程(Functional programming)

函数编程(简称FP)不只代指Haskell Scala等之类的语言,还表示一种编程思维,软件思考方式,也称面向函数编程. 编程的本质是组合,组合的本质是范畴Category,而范畴是函数的组合. 首先,什么是函数式编程,这并没有唯一定义,它只是广泛聚合了一些编程风格的特性,我们可以将它与面向对象编程OOP进行对比, 两者区别是,OOP主要聚焦于数据的区别,而FP则注重数据结构的一致性. 面向对象: 数据和对数据的操作紧紧耦合 .对象隐藏它们操作的实现细节,其他对象调用这些操作只需要通过接口. .