<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>冒号空间 &#187; 命令式编程</title>
	<atom:link href="http://blog.zhenghui.org/tag/imperative-programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Fri, 16 Jul 2010 18:33:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>冒号课堂§2.2：声明范式</title>
		<link>http://blog.zhenghui.org/2009/09/04/colon-class-2_2/</link>
		<comments>http://blog.zhenghui.org/2009/09/04/colon-class-2_2/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 15:48:57 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[函数式编程]]></category>
		<category><![CDATA[命令式编程]]></category>
		<category><![CDATA[声明式编程]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[逻辑式编程]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=341</guid>
		<description><![CDATA[<b>声明范式</b>——目标决定行动（<em>声明式编程简谈</em>）<br/>
•	命令式编程是行动导向的，因而算法是显性而目标是隐性的；声明式编程是目标驱动的，因而目标是显性而算法是隐性的<br/>
•	声明式编程重目标、轻过程，专注问题的分析和表达而不致陷入算法的迷宫，其代码也更加简洁清晰、易于修改和维护<br/>
•	归根结底，编程是寻求一种机制，将指定的输入转化为指定的输出]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第二课 重要范式(2)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>
 
<div lang="zh-CN" class="article" title="声明范式"><div class="titlepage"><div><div><h1 class="title"><a name="id671200"></a>2.2 声明范式——目标决定行动</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>声明式编程简谈</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>给我一个支点，我能挪动地球</p></div><div class="attribution"><span>—<span class="attribution">Archimedes</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    命令式编程是行动导向的，因而算法是显性而目标是隐性的；声明式编程是目标驱动的，因而目标是显性而算法是隐性的
                </p></li><li class="listitem"><p>
                    声明式编程重目标、轻过程，专注问题的分析和表达而不致陷入算法的迷宫，其代码也更加简洁清晰、易于修改和维护
                </p></li><li class="listitem"><p>
                    归根结底，编程是寻求一种机制，将指定的输入转化为指定的输出
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>什么是声明式编程？它与命令式编程有何区别？</p></li><li class="listitem"><p>什么是函数式和逻辑式？</p></li><li class="listitem"><p>变量在命令式编程和声明式编程中有何不同的涵义？</p></li><li class="listitem"><p>声明式语言有何优点？为什么没有命令式语言流行？</p></li><li class="listitem"><p>命令式语言与声明式语言有无相通之处？</p></li><li class="listitem"><p>编程的本质是什么？命令式、函数式和逻辑式分别采用了怎样的编程机制？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            冒号迅速转移了话题：“下面我们来谈谈与命令式编程相对的<span class="term">声明式编程</span>（declarative programming）。顾名思义，声明式编程由若干<span class="term">规范</span>（specification）的声明组成的，即一系列陈述句：‘已知这，求解那’，强调‘做什么’而非‘怎么做’。声明式编程是人脑思维方式的抽象，即利用数理逻辑或既定规范对已知条件进行推理或运算。”
        </p><p>
            问号询问：“声明式产生的背景是什么呢？”
        </p><p>
            “声明式编程发轫于人工智能的研究，主要包括<span class="term">函数式编程</span>（functional programming，简称FP）和<span class="term">逻辑式编程</span>（logic programming，简称LP）。其中，函数式编程将计算描述为数学函数的求值，而逻辑式编程通过提供一系列事实和规则来推导或论证结论。其实支持它们的语言出现得并不比命令式的晚多少——最早的函数式语言Lisp（<span class="strong"><strong>LIS</strong></span>t <span class="strong"><strong>P</strong></span>rocessor）已有半个世纪的历史，最早之一的逻辑式语言Prolog（<span class="strong"><strong>PRO</strong></span>gramming in <span class="strong"><strong>LOG</strong></span>ic）也与C同龄。只是由于大多数更多地用于学术研究而非商业应用，颇有些‘养在深闺人未识’啊。”冒号有些惋惜，“起源的不同决定了这两大类范式代表着迥然不同的编程理念和风格：<span class="strong"><strong>命令式编程是行动导向（Action-Oriented）的</strong></span>，因而<span class="strong"><strong>算法是显性而目标是隐性的</strong></span>；<span class="strong"><strong>声明式编程是目标驱动（Goal-Driven）的</strong></span>，因而<span class="strong"><strong>目标是显性而算法是隐性的</strong></span>。为便于说明，我们分别用三种代表性的语言来实现阶乘（factorial）运算。”
        </p><p>
            冒号在黑板上打出投影——
        </p><div class="example"><a name="id671308"></a><p class="title"><b>阶乘的三种实现：</b></p><div class="example-contents"><p><span class="emphasis"><em>C（命令式）</em></span>——</p><pre class="programlisting">
    int factorial(int n) 
    {
        int f = 1;
        for (; n &gt; 0; --n) f *= n;
        return f;
    }</pre><p><span class="emphasis"><em>Lisp（函数式）</em></span>——</p><pre class="programlisting">
    (defun factorial(n)
      (if (= n 0)
        1                               //  若n等于0，则n!等于1
        (* n (factorial(- n 1)))))      //  否则n!等于n* (n-1)</pre><p><span class="emphasis"><em>Prolog（逻辑式）</em></span>——</p><pre class="programlisting">
    // 0! 等于1
    factorial(0,1).
    // 若M等于N-1且 M!等于Fm且F等于N*Fm，则N! 等于F
    factorial(N,F) :-   M is N-1, factorial(M,Fm), F is N * Fm. </pre></div></div><br class="example-break"><p>
            冒号提问：“撇开语法细节，大家说说以上三段代码区别在哪里？”
        </p><p>
            句号沉思片刻，答道：“C明确给出了阶乘的迭代算法，而Lisp仅描述了阶乘的递归定义，Prolog则陈述了两个关于阶乘的断言。”
        </p><p>
            冒号很满意：“一针见血！第二个问题：你们更习惯哪一种思维方式？”
        </p><p>
            逗号不加思索：“当然是第一种！”
        </p><p>
            冒号微笑着说：“这证明你至少是受过一定训练的程序员。大家回想一下，当你们初学编程时，是否习惯这种思维方式？”
        </p><p>
            叹号沉吟道：“好像不太习惯<code class="code">i = i + 1</code>之类的语句。”
        </p><p> “对！”冒号的一嗓子吓了众人一跳，“我们最早接触的变量是代数方程中的x、y、z等，本质上是<span class="emphasis"><em>抽象化的符号</em></span>，变量值是该符号在给定约束条件下的允许值。而命令式编程中的变量本质上是<span class="emphasis"><em>抽象化的内存</em></span>，变量值是该内存的储存内容。通俗地说，前者好比<span class="emphasis"><em>姓名</em></span>，所指之人是固定的；后者好比<span class="emphasis"><em>住址</em></span>，所住之人是变化的。此外，等号在代数中是一种约束，而在许多命令式语言中则表示赋值。因此<code class="code">i = i + 1</code>可以在命令式编程中出现，但绝不可能在数学推理中出现<a class="link" href="#note1"><sup>[1]</sup></a>——除非在反证法中。”
        </p><p>
            叹号又道：“现在回头再看代数，反倒有些不习惯了。”
        </p><p>
            “这就是思维的<span class="emphasis"><em>定势效应</em></span>。”冒号感慨道，“声明式编程让我们重回数学思维：函数式编程类似代数中的表达式变换和计算，逻辑式编程则类似数理逻辑推理。其中的变量也如数学中的一样，是抽象符号而非内存地址，因此没有赋值运算，不会产生变量被改写的<span class="emphasis"><em>副作用</em></span>（side-effect），也不存在内存分配和释放的问题。这既简化了代码，也减少了调试——不妨想一想，有多少bug是由于某个变量被意外改写或内存管理不慎而造成的？”
        </p><p>
            问号问道：“声明式语言与命令式语言看来是两个世界的产物，它们是否有相通之处？”
        </p><p>
            冒号答道：“首先，所有高级语言都建立于低级语言之上，最终转化为机器语言，声明式语言也不例外。其次，声明式语言与命令式语言并非泾渭分明，而是互相交叉渗透的。一些‘非纯粹’ 的声明式语言也提供变量赋值和流程控制，而一些命令式语言也在逐渐发展，通过利用其他程序或增加新的语言特征来实现声明式编程。总的说来，在命令式语言中融入声明式的元素应当是一种趋势。尤其是函数式，它的一些特征已经在许多命令式语言中得到了支持。比较而言，声明式编程重目标、轻过程，专注问题的分析和表达而不致陷入算法的迷宫，其代码也更加简洁清晰、易于修改和维护。从这种意义上说，声明式语言天然地就比命令式语言更高级。上节课提到的前三代计算机语言基本上都是命令式的，而后两代基本上都是声明式的，由此可见一斑。”
        </p><p>
            句号一拍脑袋：“命令式是模拟电脑的，声明式是模拟人脑的，人脑当然比电脑高级啦。”
        </p><p>
            冒号另有佐证：“早在命令式语言引入函数从而进化为过程式语言时，就已经开始向声明式过渡了。何以见得？比方说调用一个函数的语句：<code class="code">doWhat()</code>，这不正是在声明‘what to do’吗？至于‘how to do’，即函数的具体实现细节，则不劳调用者费心。这种声明式的风格，提高了语言的抽象能力和开发效率，促成了语言的升级。”
        </p><p>
            逗号仍然有些疑惑：“既然声明式编程有这么多好处，为什么命令式语言不仅占大多数，而且流行程度也不减呢？”
        </p><p>
             冒号回答：“编程语言的流行程度与其擅长的领域关系密切。声明式语言——尤其是函数式语言和逻辑式语言——擅长基于数理逻辑的应用，如人工智能、符号处理、数据库、编译器等，对基于业务逻辑的、尤其是交互式或事件驱动型的应用就不那么得心应手了。而大多数软件是面向用户的，交互性强、多为事件驱动、业务逻辑千差万别，显然命令式语言在此更有用武之地。”
        </p><p>
            大家频频颔首。
        </p><p>
            “值得指出的是，声明式编程并不仅仅局限于函数式和逻辑式。”冒号旋即补充道，“比方说，C#中的attribute、Java中的annotation和XDoclet库等采用的也是具有声明式特征的<span class="term">属性导向式编程</span>（Attribute-Oriented Programming，简称@OP）。再比如，Prograph<a class="link" href="#note2"><sup>[2]</sup></a> 、SISAL<a class="link" href="#note3"><sup>[3]</sup></a>等<span class="term">数据流语言</span>（dataflow language）采用的<span class="term">数据流式编程</span>（Dataflow Programming）与函数式编程有不少共同点，同样属于声明式的范畴。还有一些语言如Oz、CHIP等支持与逻辑式编程相交的<span class="term">约束式编程</span>（Constraint Programming）<a class="link" href="#note4"><sup>[4]</sup></a>。此外，大家熟悉的数据库语言SQL，<span class="term">样式语言</span>XSLT、CSS，<span class="term">标记语言</span>HTML、XML、SVG，<span class="term">规范语言</span>IDL（Interface Description Language）等等都是声明式的。算上它们，声明式语言所占的比例也是非常可观的。此前之所以没有提及，一方面，不少声明式语言采用的范式并没有专门的名称；另一方面，这些语言大多是<span class="term">领域特定语言</span>，并且不少并非<span class="term">图灵完备的</span>，有的连运算都没有。毕竟，目前我们的重点还是放在<span class="term">通用编程语言</span>上。”
        </p><p>
            问号突然想到了什么，指着投影问：“这里用Lisp实现阶乘的方法不也可以用在C上吗？”
        </p><p>
            冒号点点头，写下一段代码——
        </p><pre class="programlisting">
int factorial(int n) 
{
    return n == 0 ? 1 : n * factorial(n - 1);
}</pre><p>
            “这是C的递归实现。”冒号娓娓道来，“除了细微的语法差别外，二者的确很相似，这说明用命令式语言也可以讲出声明式的味道。实际上，命令式语言提倡迭代而不鼓励递归，早期的Fortran 甚至都不支持递归。一则迭代比递归更符合命令式的思维模式，因为前者贴近机器语言而后者贴近数学语言；二则除<span class="term">尾递归</span>（tail recursion）<a class="link" href="#note5"><sup>[5]</sup></a>外，一般递归比迭代的开销（overhead）大。相反，声明式语言提倡递归而不支持迭代<a class="link" href="#note6"><sup>[6]</sup></a>。就语法而言，它不允许迭代中的循环变量；就视角而言，迭代着眼微观过程而递归着眼宏观规律。”
        </p><p>
            叹号轻叹：“原来貌似普通的迭代和递归有那么多道道！”
        </p><p>
            “任何语言都难脱命令式或声明式的窠臼。事实上，凡是非命令式的编程都可归为声明式编程。因此，命令式、函数式和逻辑式是最核心的三种范式。为清楚起见，我们用一幅图来表示它们之间的关系。”说罢，冒号换了一个幻灯片——
        </p><div class="figure"><a name="id671551"></a><p class="title"><b>图2-4. 编程范式的简单分类</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure2-4.jpg" alt="编程范式的简单分类"></div></div></div><br class="figure-break"><p>
            末了，冒号归纳道：“归根结底，<span class="strong"><strong>编程是寻求一种机制，将指定的输入转化为指定的输出</strong></span>。三种范式对此提供了截然不同的解决方案：命令式把程序看作一个<span class="emphasis"><em>自动机</em></span>，输入是<span class="emphasis"><em>初始状态</em></span>，输出是<span class="emphasis"><em>最终状态</em></span>，编程就是设计一系列指令，通过自动机执行以完成状态转变；函数式把程序看作一个<span class="emphasis"><em>数学函数</em></span>，输入是<span class="emphasis"><em>自变量</em></span>，输出是<span class="emphasis"><em>因变量</em></span>，编程就是设计一系列函数，通过表达式变换以完成计算；逻辑式把程序看作一个<span class="emphasis"><em>逻辑证明</em></span>，输入是<span class="emphasis"><em>题设</em></span>，输出是<span class="emphasis"><em>结论</em></span>，编程就是设计一系列命题，通过逻辑推理以完成证明。绘成表格如下（如表2-1所示）——” 
        </p><div class="table"><a name="id671610"></a><p class="title"><b>表2-1. 三种核心编程范式的比较</b></p><div class="table-contents"><table summary="三种核心编程范式的比较" border="1"><colgroup><col><col><col><col><col><col></colgroup><thead><tr><th>范式</th><th>程序</th><th>输入</th><th>输出</th><th>程序设计</th><th>程序运行</th></tr></thead><tbody><tr><td>命令式</td><td>自动机</td><td>初始状态</td><td>最终状态</td><td>设计指令</td><td>命令执行</td></tr><tr><td>函数式</td><td>数学函数</td><td>自变量</td><td>因变量</td><td>设计函数</td><td>表达式变换</td></tr><tr><td>逻辑式</td><td>逻辑证明</td><td>题设</td><td>结论</td><td>设计命题</td><td>逻辑推理</td></tr></tbody></table></div></div><br class="table-break"><p>
            冒号见众人微显难色，宽慰道：“这部分理论性稍微强了些，对函数式和逻辑式也仅作了描述性说明，并未深入展开。不解之处，大可不必介怀，撒下的种子总有一天会萌动。先休息片刻，不要走开，广告之后更精彩。”
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    数学中应该用类似<span class="mathphrase">i<sub>n+1</sub> = i<sub>n</sub> + 1</span>的表示法。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    Prograph即<span class="strong"><strong>Pro</strong></span>gramming in <span class="strong"><strong>Graph</strong></span>ics，是一种可视化的、对象导向（OO）的数据流语言，它用图表（diagram）来取代文本编码。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    SISAL即<span class="strong"><strong>S</strong></span>treams and <span class="strong"><strong>I</strong></span>teration in a <span class="strong"><strong>S</strong></span>ingle <span class="strong"><strong>A</strong></span>ssignment <span class="strong"><strong>L</strong></span>anguage，是一种函数式数据流语言，擅长并行科学计算。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    约束式编程通过数据之间的约束关系来进行运算。它可以借助逻辑推理机制或其他数学和算法技巧来实现。有一种观点认为：用函数式、逻辑式或约束式三者之一的语言来编写程序，即是声明式编程。这种以编程语言反过来定义编程范式的说法值得商榷，但从中可看出约束式编程的代表性。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    尾递归是一种特殊的递归，其递归调用出现在函数的最后一步运算（尾部）。这类递归很容易通过手工或编译器转化为迭代形式，以优化性能。
                </p></li><li class="listitem"><p><a name="note6"></a>
                    有些声明式语言（例如Lisp的一个变种Scheme）虽然支持迭代，但一般是用尾递归来实现的。从本质上说，这只是一种语法上的甜头（syntactic sugar）。它与普通迭代的区别在于：前者的循环变量是重新绑定（rebind）的，而后者的循环变量是重复赋值（reassign）的。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    	命令式编程通过一系列改变程序状态的指令来完成计算，声明式编程只描述程序应该完成的任务。命令式编程模拟电脑运算，是行动导向的，关键在于定义解法，即“怎么做”，因而算法是显性而目标是隐性的；声明式编程模拟人脑思维，是目标驱动的，关键在于描述问题，即“做什么”，因而目标是显性而算法是隐性的。
                </p></li><li class="listitem"><p>
                    函数式编程通过数学函数的表达式变换和计算来求值。
                </p></li><li class="listitem"><p>
                    逻辑式编程通过一系列事实和规则，利用数理逻辑来推导或论证结论。
                </p></li><li class="listitem"><p>
                    命令式编程中的变量代表抽象化的内存，所存内容可能改变。声明式编程中的变量代表抽象化的符号，所指对象一般不会改变。
                </p></li><li class="listitem"><p>
                    声明式编程专注问题的分析和表达而不是算法实现，不用指明执行顺序，一般没有或极少副作用，也不存在内存管理问题。这些都大大降低了编程的复杂度，同时也非常适合于并发式计算。
                </p></li><li class="listitem"><p>
                    编程语言的流行程度与其擅长的领域密切相关。函数式语言和逻辑式语言擅长基于数理逻辑的应用，命令式语言擅长基于业务逻辑的、尤其是交互式或事件驱动型的应用。
                </p></li><li class="listitem"><p>
                    声明式语言与命令式语言之间并无绝对的界限，它们均建立于低级语言之上，并且互相渗透融合。
                </p></li><li class="listitem"><p>
                    在命令式语言中引入函数或过程，是一种向声明式风格的趋近。
                </p></li><li class="listitem"><p>
                    编程是寻求一种机制，将指定的输入转化为指定的输出。
                </p></li><li class="listitem"><p class="simpara"> 三种核心编程范式采用如下不同的机制——</p><p class="simpara">命令式：自动机机制，通过设计指令完成从初始态到最终态的转变。</p><p class="simpara">函数式：数学变换机制，通过设计函数完成从自变量到因变量的计算。</p><p class="simpara">逻辑式：逻辑证明机制，通过逻辑推理完成从题设到结论的证明。</p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Elena Bolshakova．PROGRAMMING PARADIGMS IN COMPUTER SCIENCE EDUCATION．International Journal &#8220;Information Theories &amp; Applications&#8221;，2005，Vol.12：285-290
                </p></li><li class="listitem"><p>
                    Ravi Sethi．Programming Languages: Concepts &amp; Constructs(英文版第2版)．北京：机械工业出版社，2002．301-340,423-470
                </p></li><li class="listitem"><p>
                    Wikipedia．Declarative programming．<a class="link" href="http://en.wikipedia.org/wiki/Declarative_programming" target="_top">http://en.wikipedia.org/wiki/Declarative_programming</a>
                </p></li></ol></div></div></div>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F04%2Fcolon-class-2_2%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A72.2%EF%BC%9A%E5%A3%B0%E6%98%8E%E8%8C%83%E5%BC%8F">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/04/colon-class-2_2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>冒号课堂§2.1：命令范式</title>
		<link>http://blog.zhenghui.org/2009/09/03/colon-class-2_1/</link>
		<comments>http://blog.zhenghui.org/2009/09/03/colon-class-2_1/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 08:08:52 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[命令式编程]]></category>
		<category><![CDATA[流程图]]></category>
		<category><![CDATA[结构化编程]]></category>
		<category><![CDATA[编程范式]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=322</guid>
		<description><![CDATA[<b>命令范式</b>——一切行动听指挥（<em>命令式编程简谈</em>）<br/>
•	（命令式编程）其世界观是：程序是由若干行动指令组成的有序列表；其方法论是：用变量来储存数据，用语句来执行指令<br/>
•	（结构化编程）在微观上，主张循规守矩；在宏观上，主张分而治之<br/>
•	一个按结构化编程思想设计的流程图，每个模块大小适中、模块之间关系简明、模块内部线路清晰，单从视觉上就会给人一种美感]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center;"><span style="font-family: 宋体;">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体;">第二课 重要范式（1）</span></strong>

<p><strong><span style="font-family: 宋体;">课前导读</span></strong></p>
<p style="text-indent: 18pt;"><span style="font-family: 宋体;">这一课讨论了五个最重要的编程范式：命令式、函数式、逻辑式、对象式和并发式。这些只是入门性的介绍，读者领会其精神即可，细节上不必过于在意。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-family: 宋体;">本课共分四节——</span></p>
<p style="text-indent: 18pt;"><em>1.</em><em><span style="font-family: 宋体;">命令范式——一切行动听指挥</span></em></p>
<p style="text-indent: 18pt;"><em>2.</em><em><span style="font-family: 宋体;">声明范式——目标决定行动</span></em></p>
<p style="margin-left: 18pt;"><em>3.</em><em><span style="font-family: 宋体;">对象范式——民主制社会的编程法则</span></em></p>
<p style="margin-left: 18pt;"><em>4.</em><em><span style="font-family: 宋体;">并发范式——合作与竞争</span></em></p>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>
        
        <div lang="zh-CN" class="article" title="命令范式"><div class="titlepage"><div><div><h1 class="title"><a name="id519232"></a>2.1 命令范式——一切行动听指挥</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>命令式编程简谈</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>人生最伟大的目标是行动</p></div><div class="attribution"><span>—<span class="attribution">《洛克菲勒的忠告》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    （命令式编程）其世界观是：程序是由若干行动指令组成的有序列表；其方法论是：用变量来储存数据，用语句来执行指令
                </p></li><li class="listitem"><p>（结构化编程）在微观上，主张循规守矩；在宏观上，主张分而治之</p></li><li class="listitem"><p>
                    一个按结构化编程思想设计的流程图，每个模块大小适中、模块之间关系简明、模块内部线路清晰，单从视觉上就会给人一种美感
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>什么是命令式编程？它为什么是最常见的编程范式？</p></li><li class="listitem"><p>什么是结构化编程？结构化编程的主要思想是什么？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            第二课伊始，冒号开门见山：“首先介绍一下最原始也是我们最熟悉的编程范式：<span class="term">命令式编程</span>（imperative programming）。用命令式编写的程序由命令序列组成，即一系列祈使句：‘先做这，再做那’，强调‘怎么做’。更学术点说，命令式编程是电脑——准确地讲，是<span class="term">冯•诺伊曼机</span>（von Neumann machine）——运行机制的抽象，即依序从内存中获取指令和数据然后去执行。从范式的角度看，<span class="strong"><strong>其世界观是：程序是由若干行动指令组成的有序列表；其方法论是：用变量来储存数据，用语句来执行指令</strong></span>。”
        </p><p>
            逗号小声嘟囔着：“我们用的编程语言不都是命令式的吗？”
        </p><p>
            “应该说绝大多数语言是命令式的，但非命令式的语言也是存在的。关于后者，我们稍后再议。” 冒号纠正道，“这也在情理之中。语言的演化是渐进的，大多数语言追根溯源是汇编语言的升级，而作为与机器语言一一对应的汇编语言自然是命令式的，因而这种范式最为传统和普及。”
        </p><p>
            不料问号竟穷追不舍：“为什么机器语言就一定得是命令式呢？”
        </p><p>
            “我很欣赏你这种打破砂锅问到底的精神，不过你可以问到底，我却不敢保证能答到底哦。”冒号有些逗趣地说。
        </p><p>
            问号略带腼腆地笑了。
        </p><p>
            “从理论上而言，完全可以有非命令式的机器语言存在，前提是计算机采用了特殊的硬件实现，比如非冯•诺伊曼结构的<span class="term">数据流机</span>（dataflow machine）和<span class="term">归约机</span>（reduction machine）。但这类计算机并未流行于市，相应的机器语言自然罕见了<a class="link" href="#note1"><sup>[1]</sup></a>。”冒号还是给出了理由。
        </p><p>
            引号问：“命令式编程与人们常说的过程式编程是一回事吗？”
        </p><p>
            “严格说来，<span class="term">过程式编程</span>（procedural programming）是指引入了<span class="term">过程</span>（procedure）、<span class="term">函数</span>（function）或<span class="term">子程序</span>（subroutine/subprogram）的命令式编程。但由于现代的命令式语言均具备此特征，故二者往往不加区分。”冒号回应道。
        </p><p>
            句号认为：“由于常用的语言基本上都是命令式的，其思想也与计算机的运行机制相符，一切对我们来说，似乎都是自然而然的事。”
        </p><p>
            “单纯的命令式思想的确很朴素，毋庸赘述。” 冒号承认，“但有必要提一下<span class="term">结构化编程</span>（structured programming或简称SP），它是在过程式编程的基础上发展起来的。其本质是一种编程原则，提倡代码应具有清晰的逻辑结构，以保证程序易于读写、测试、维护和优化。可别小瞧它，在上世纪六十年代首次爆发的软件危机中，它曾起着中流砥柱的作用，就像后来的OOP一样。Pascal正是遵循结构化编程原则而设计的一种教学语言，当年也是风光无限。为直观起见，我们用图来表现程序的结构化特征——”
        </p><div class="figure"><a name="id519336"></a><p class="title"><b>图2-1. 非严格的结构化程序框图</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure2-1.jpg" alt="非严格的结构化程序框图"></div></div></div><br class="figure-break"><p>
            “这是一个<span class="term">流程图</span>（flowchart），或称<span class="term">程序框图</span>，它描述了一个简单程序：用户从标准输入中键入算术表达式，程序打印出结果，如此循环往复，直到用户输入字符‘q’为止。”冒号解释道，“若以纯粹的结构化编程的标准来衡量，该流程图并未达标。”
        </p><p>
            叹号有些惊讶：“这个图不是再清晰不过了吗？”
        </p><p>
            “根据结构化定理（structured program theorem）<a class="link" href="#note2"><sup>[2]</sup></a>，任何程序都可用顺序（concatenation）、选择（selection）和循环（repetition）等三种基本控制结构来表示。”冒号画了几幅图——
        </p><div class="figure"><a name="id519382"></a><p class="title"><b>图2-2. 三种基本控制结构：顺序、选择和循环</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure2-2.jpg" alt="三种基本控制结构：顺序、选择和循环"></div></div></div><br class="figure-break"><p>
            冒号指点着黑板：“结构化编程就是在三种基本结构的基础上进行嵌套组合。如果将每个基本结构看作基本电器元件，编程就是将这些元件组装成复杂的电路。请注意，所有基本元件都满足‘单入口、单出口’（single entry, single exit，简称SESE）的原则，这使得电路井井有条，不会串线缠绕。”
        </p><p>
            引号已经看出：“上面的流程图无法用基本结构来组合，所以不是标准的结构化程序。”
        </p><p>
            冒号提出要求：“你能改造一下吗？”
        </p><p>
            引号走上讲台，在前图的基础上作了些许调整——
        </p><div class="figure"><a name="id519414"></a><p class="title"><b>图2-3. 严格的结构化程序框图</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure2-3.jpg" alt="严格的结构化程序框图"></div></div></div><br class="figure-break"><p>
            “嗯，不错。这下流程图可以拆解为基本结构了。”冒号表示认可，“二者的区别在于前者利用了break语句，在循环途中退出，后者通过引入quit标志（flag）保证了循环的完整性。”
        </p><p>
            逗号的脸上写下一个大大的问号：“难道连break语句都不能用吗？”
        </p><p>
            “break语句只是在循环体内部的跳转，合理地使用它能简化代码，不致影响整体结构，大可不必拘泥于教条。但goto语句可以跳到程序过程中的任一点，造成<span class="emphasis"><em>静态程序</em></span>（static program）与<span class="emphasis"><em>动态进程</em></span>（dynamic process）之间的差异，影响程序可读性，是要竭力避免的<a class="link" href="#note3"><sup>[3]</sup></a>。”冒号如是说道，“结构化编程的思想包括两方面。在微观上，主张循规守矩，采用顺序、选择和循环三种逻辑结构，摒弃或限制goto语句<a class="link" href="#note4"><sup>[4]</sup></a>，以避免杂乱无章的代码。在宏观上，主张分而治之（divide and conquer），采用‘自顶向下（top-down）’ <a class="link" href="#note5"><sup>[5]</sup></a> 的设计，通过<span class="emphasis"><em>模块化</em></span>将一个较为复杂的系统分解为若干相对简单的子系统，每个子系统可以独立地进一步分解，直到容易编码实现为止。这两方面是互为因果、互为保障的——由基本结构拼装而成的系统一定是模块清晰、层次分明的；反之，系统逐步分解到最后，一定会演化成基本结构。”
        </p><p>
            叹号产生一个想法：“能从程序的流程图上看出结构化编程与非结构化编程之间的区别吗？”
        </p><p>
            “一个按结构化编程思想设计的流程图，每个模块大小适中、模块之间关系简明、模块内部线路清晰，单从视觉上就会给人一种美感。相反，如果采用非结构化的设计，流程图往往结构如杂草般松散紊乱、脉络如迷宫般错综复杂、箭头如线头般剪不断理还乱，情节严重的会导致读者头晕目眩乃至抓狂吐血。”冒号极尽夸张之能事。
        </p><p>
            众人掩口失声。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    数据流机支持数据流式语言，归约机支持函数式语言。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    见参考文献【1】。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    1967年，E.W. Dijkstra 在其著名论文“Goto statement considered harmful”中指出goto语句的危害性，主张废除这种用法。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    1974年，Donald Knuth在论文“Structured Programming with Goto Statements”中认为goto语句仍有其合理性，应该限制而不是完全摒弃。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    也称“自顶向下、逐步求精”。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    命令式编程是冯•诺伊曼机运行机制的抽象。它把程序看作是由若干行动指令组成的有序列表，并用变量来储存数据，用语句来执行指令。
                </p></li><li class="listitem"><p>
                    结构化编程是过程式编程的一种原则，其主要思想是：提倡在宏观上采用‘自顶向下’的设计，微观上采用顺序、选择和循环的逻辑结构，摒弃或限制goto语句，以保证程序结构清晰、易于调试和维护。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Corrado Böhm，Giuseppe Jacopini．Flow Diagrams, Turing Machines and Languages with Only Two Formation Rules． Communications of the ACM，1966，9(5)：366–371
                </p></li><li class="listitem"><p>
                    Ravi Sethi．Programming Languages: Concepts &amp; Constructs, 2<sup>nd</sup> Ed.．Reading, MA：Addison Wesley，1996．59-77
                </p></li></ol></div></div></div>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F03%2Fcolon-class-2_1%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A72.1%EF%BC%9A%E5%91%BD%E4%BB%A4%E8%8C%83%E5%BC%8F">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/03/colon-class-2_1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
