<?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>Erlang-China &#187; language</title>
	<atom:link href="http://erlang-china.org/tag/language/feed" rel="self" type="application/rss+xml" />
	<link>http://erlang-china.org</link>
	<description>erlang 中文社区</description>
	<lastBuildDate>Thu, 21 Apr 2011 10:01:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.1</generator>
		<item>
		<title>回“老赵”关于“Erlang中最大的问题”</title>
		<link>http://erlang-china.org/study/puzzle-in-erlang_pattern_match.html</link>
		<comments>http://erlang-china.org/study/puzzle-in-erlang_pattern_match.html#comments</comments>
		<pubDate>Fri, 10 Jul 2009 07:37:53 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>
		<category><![CDATA[best_practise]]></category>
		<category><![CDATA[language]]></category>
		<category><![CDATA[pattern_match]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=563</guid>
		<description><![CDATA[活跃在博客园的“老赵”，是一位研究 .NET 非常深入的同学(因为我本人也是老赵——jackyz.zhao，所以，特地加了引号)。他最近很关注“在 .NET 下实现 Erlang 语言特性”的课题，并为此写了一系列的技术文章，相当不错，我一直都在关注。他自己写了一个名为 ActorLite 的小东西，此前做过介绍，是个不错的尝试。 最近“老赵”同学写了一篇《一种适合C# Actor的消息执行方式(上)》，其中提到“(在消息执行上) Erlang 中最大的问题”。这是一个很有意思的观点，而且因为富于代表性因而显得很有价值，很有必要拿出来和大家探讨。 其中提到： Erlang的优势与缺陷 　　Erlang在消息执行方式上的优势在于灵活。Erlang是弱类型语言，在实现的时候可以任意调整消息的内容，或是模式的要求。在 Erlang进行模式匹配时往往有种约定：使用“原子”来表示“做什么”，而使用“绑定”来获取操作所需要的“数据”，这种方式避免了冗余的cast和赋值，在使用的时候颇为灵活。然而，世上没有完美的事物，Erlang的消息执行方式也有缺陷，而且是较为明显的缺陷。 　　首先，Erlang的数据抽象能力实在太弱。如果编写一个略显复杂的应用程序，您会发现程序里充斥着复杂的元组。您可能会疲于应对那些拥有7、 8个单元（甚至跟多）的元组，一个一个数过来到底某个绑定匹配的是第几项，它的含义究竟是什么——一旦搞错，程序便会出错，而且想要调试都较为困难。因此，也有人戏称Erlang是一门“天生会损害人视力的语言”（令人惊讶的是，那篇文章居然搜不到了，我们只能从搜索引擎上看出点痕迹了）。 　　而我认为，这并不是Erlang语言中最大的问题，Erlang中最大的问题也是其“弱类型”特性。例如，现在有一个公用的Service Locator服务，任意类型的Actor都会像SL发送一个消息用于请求某个Service的位置，SL会在得到请求之后，向请求方发送一条消息表示应答。试想，如果SL的功能需要有所修改，作为回复的消息结构产生了变化，那么我们势必要修改每一个请求方中所匹配的模式。由于消息的发送方和接受方在实际上完全分离，没有基于任何协议，因此静态检查几乎无从做起。一旦遇到这种需要大规模的修改的情况，Erlang程序便很容易产生差错。因为一旦有所遗漏，系统便无法正常执行下去了。 这的确是对于动态类型语言很常见到的担心，而且，确实，如果不加注意会成为严重的问题。这种困扰确实是因为 Erlang 的“动态类型”和“基于消息”而造成的。但，这并非无解，实际上，在 Erlang 编程规范之中，已经给出了解决方案。 通常而言，Erlang 中的消息应该是以“控制流”为主，在消息的数据结构表达上，不同的消息通常都对应着不同的处理流程，在这里“控制”是消息中最为关注的内容。为此我们可以简单的引入一个 atom 来予以表达，这就是 Tag Messages 的最佳实践： 5.7 Tag messages All messages should be tagged. This makes the order in the receive statement less important and the implementation of [...]]]></description>
			<content:encoded><![CDATA[<p>活跃在博客园的“<a href="http://jeffreyzhao.cnblogs.com/" target=_blank>老赵</a>”，是一位研究 .NET 非常深入的同学(因为我本人也是老赵——jackyz.zhao，所以，特地加了引号)。他最近很关注“在 .NET 下实现 Erlang 语言特性”的课题，并为此写了一系列的技术文章，相当不错，我一直都在关注。他自己写了一个名为 <a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/05/11/a-simple-actor-model-implementation.html" target=_blank>ActorLite</a> 的小东西，此前做过介绍，是个不错的尝试。</p>
<p>最近“老赵”同学写了一篇《<a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/07/09/message-execution-model-for-c-sharp-actor-1-pattern-matching-in-erlang.html" target=_blank>一种适合C# Actor的消息执行方式(上)</a>》，其中提到“(在消息执行上) Erlang 中最大的问题”。这是一个很有意思的观点，而且因为富于代表性因而显得很有价值，很有必要拿出来和大家探讨。<br />
<span id="more-563"></span><br />
其中提到：</p>
<blockquote><p>
<strong>Erlang的优势与缺陷</strong></p>
<p>　　Erlang在消息执行方式上的优势在于灵活。Erlang是弱类型语言，在实现的时候可以任意调整消息的内容，或是模式的要求。在 Erlang进行模式匹配时往往有种约定：使用“原子”来表示“做什么”，而使用“绑定”来获取操作所需要的“数据”，这种方式避免了冗余的cast和赋值，在使用的时候颇为灵活。然而，世上没有完美的事物，Erlang的消息执行方式也有缺陷，而且是较为明显的缺陷。</p>
<p>　　首先，Erlang的数据抽象能力实在太弱。如果编写一个略显复杂的应用程序，您会发现程序里充斥着复杂的元组。您可能会疲于应对那些拥有7、 8个单元（甚至跟多）的元组，一个一个数过来到底某个绑定匹配的是第几项，它的含义究竟是什么——一旦搞错，程序便会出错，而且想要调试都较为困难。因此，也有人戏称Erlang是一门“天生会损害人视力的语言”（令人惊讶的是，那篇文章居然搜不到了，我们只能从搜索引擎上看出点痕迹了）。</p>
<p>　　而我认为，这并不是Erlang语言中最大的问题，Erlang中最大的问题也是其“弱类型”特性。例如，现在有一个公用的Service Locator服务，任意类型的Actor都会像SL发送一个消息用于请求某个Service的位置，SL会在得到请求之后，向请求方发送一条消息表示应答。试想，如果SL的功能需要有所修改，作为回复的消息结构产生了变化，那么我们势必要修改每一个请求方中所匹配的模式。由于消息的发送方和接受方在实际上完全分离，没有基于任何协议，因此静态检查几乎无从做起。一旦遇到这种需要大规模的修改的情况，Erlang程序便很容易产生差错。因为一旦有所遗漏，系统便无法正常执行下去了。
</p></blockquote>
<p>这的确是对于动态类型语言很常见到的担心，而且，确实，如果不加注意会成为严重的问题。这种困扰确实是因为 Erlang 的“动态类型”和“基于消息”而造成的。但，这并非无解，实际上，在 <a href="http://www.erlang.se/doc/programming_rules.shtml" target=_blank>Erlang 编程规范</a>之中，已经给出了解决方案。</p>
<p>通常而言，Erlang 中的消息应该是以“控制流”为主，在消息的数据结构表达上，不同的消息通常都对应着不同的处理流程，在这里“控制”是消息中最为关注的内容。为此我们可以简单的引入一个 atom 来予以表达，这就是 Tag Messages 的最佳实践：</p>
<blockquote><p>
<strong> 5.7 Tag messages</strong></p>
<p>All messages should be tagged. This makes the order in the receive statement less important and the implementation of new messages easier.</p>
<p>Don&#8217;t program like this:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp; </span><span style="color: Green;">receive</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;...<br />&nbsp;&nbsp; &nbsp;{</span><span style="color: Blue;">Mod</span><span style="color: Gray;">, </span><span style="color: Blue;">Funcs</span><span style="color: Gray;">, </span><span style="color: Blue;">Args</span><span style="color: Gray;">} -&gt; </span><span style="color: #ffa500;">% Don't do this</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">apply</span><span style="color: Olive;">(</span><span style="color: Blue;">Mod</span><span style="color: Gray;">, </span><span style="color: Blue;">Funcs</span><span style="color: Gray;">, </span><span style="color: Blue;">Args</span><span style="color: Gray;">},<br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp;...<br />&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></div></div>
<p>The new message {get_status_info, From, Option} will introduce a conflict if it is placed below the {Mod, Func, Args} message.</p>
<p>If messages are synchronous, the return message should be tagged with a new atom, describing the returned message. Example: if the incoming message is tagged get_status_info, the returned message could be tagged status_info. One reason for choosing different tags is to make debugging easier.</p>
<p>This is a good solution:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp; </span><span style="color: Green;">receive</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;...<br />&nbsp;&nbsp; &nbsp;{</span><span style="color: Blue;">execute</span><span style="color: Gray;">, </span><span style="color: Blue;">Mod</span><span style="color: Gray;">, </span><span style="color: Blue;">Funcs</span><span style="color: Gray;">, </span><span style="color: Blue;">Args</span><span style="color: Gray;">} -&gt; </span><span style="color: #ffa500;">% Use a tagged message.</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">apply</span><span style="color: Olive;">(</span><span style="color: Blue;">Mod</span><span style="color: Gray;">, </span><span style="color: Blue;">Funcs</span><span style="color: Gray;">, </span><span style="color: Blue;">Args</span><span style="color: Gray;">},<br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp;{</span><span style="color: Blue;">get_status_info</span><span style="color: Gray;">, </span><span style="color: Blue;">From</span><span style="color: Gray;">, </span><span style="color: Blue;">Option</span><span style="color: Gray;">} -&gt;<br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">From</span><span style="color: Gray;"> ! {</span><span style="color: Blue;">status_info</span><span style="color: Gray;">, </span><span style="color: Blue;">get_status_info</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">},<br />&nbsp;&nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">;&nbsp; &nbsp; <br />&nbsp;&nbsp; &nbsp;...<br />&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></div></div>
</blockquote>
<p>可以相信，一段庞杂的代码，在经过一番这样对 Message 本身的设计和重构之后，最终都能让其恢复“秩序与美感”。而消息中的其他参数，如果其处理逻辑非常复杂的话，那么带有模式匹配的子函数，又或着是 Tuple/Record 正是其用武之地。</p>
<p>上面我们提到了“对 Message 的设计和重构”，实际上，这只是问题的一个方面。另外一个方面是：无论 Message 的“协议”设计得有多精巧，其对外的接口都不应该用消息来表达，而应该是“接口函数”的形式。</p>
<p>Erlang 系统之中的消息是极度灵活的系统，但它并不适合用来作为模块之间的接口，因为它过于灵活。更加适合这一角色的设施是“函数”。用来充当这样角色的函数就被称作“接口函数”，在其实现代码中，除了“按照约定的格式发消息以外”什么别的也不做——因为它包装的正是以消息为载体的交互“协议”。它是函数，有着严格的语法检查，而且可以在多个模块之间重用。一旦需要修改消息协议，起隔离作用的“接口函数”就会体现出其存在的巨大价值。</p>
<blockquote><p>
<strong>5.10 Interface functions</strong></p>
<p>Use functions for interfaces whenever possible, avoid sending messages directly. Encapsulate message passing into interface functions. There are cases where you can&#8217;t do this.</p>
<p>The message protocol is internal information and should be hidden to other modules.</p>
<p>Example of interface function:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">fileserver</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />-</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">stop</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">open_file</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, ...</span><span style="color: Olive;">])</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">open_file</span><span style="color: Olive;">(</span><span style="color: Blue;">FileName</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp; </span><span style="color: Blue;">fileserver</span><span style="color: Gray;"> ! {</span><span style="color: Blue;">open_file_request</span><span style="color: Gray;">, </span><span style="color: Blue;">FileName</span><span style="color: Gray;">},<br />&nbsp; </span><span style="color: Green;">receive</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;{</span><span style="color: Blue;">open_file_response</span><span style="color: Gray;">, </span><span style="color: Blue;">Result</span><span style="color: Gray;">} -&gt; </span><span style="color: Blue;">Result</span><span style="color: Gray;"><br />&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.<br />&nbsp;<br />...</span><span style="color: Blue;">code</span><span style="color: Gray;">...</span></div></div>
</blockquote>
<p>Erlang 是动态语言，对其进行静态检查比较困难(并非不能 R13 已经有所动作)。但，并不是说没有静态检查就会寸步难行。Erlang 同样重要的语法特性是它还是函数式语言，遇到有疑惑的地方，不妨以函数的角度来思考。</p>
<p>感谢 Arbow 的分享。感谢 JeffreyZhao 的写作。</p>
<p>Erlang 语言素有“难学”的名声，其中一个原因就是因为虽然其语法十分简单，但常会让人心生 “就这样了，然后呢？” 之惑——因为过于灵活而无所适从，而且也不存在着显而易见的正确用法。这种困扰通常要在有了一定的实践经验之后才会渐渐消散。换句话说，在“学会”和“用好”之间存在着一堵模模糊糊的墙，而这一“未知区域”又需要一定的耐心和经验方可穿越。</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/puzzle-in-erlang_pattern_match.html/feed</wfw:commentRss>
		<slash:comments>165</slash:comments>
		</item>
	</channel>
</rss>

