<?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; study</title>
	<atom:link href="http://erlang-china.org/category/study/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>CouchDB —— 可以期待的美好未来</title>
		<link>http://erlang-china.org/study/couchdb_good_future_to_expect.html</link>
		<comments>http://erlang-china.org/study/couchdb_good_future_to_expect.html#comments</comments>
		<pubDate>Tue, 16 Mar 2010 18:38:07 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>
		<category><![CDATA[CouchAPP]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=675</guid>
		<description><![CDATA[有关 CouchDB 的最新动向是： Damien Katz 已经离开了 IBM ，他和他的团队，在 200w $ 投资的帮助之下，开始创业。美国投资人的魄力与专业素养，让我这个中国软件人羡慕不已，什么时候我们中国也会出现这种“纯粹谈技术就能够决定是否投你”的投资人呢？新公司名叫 Couch IO (请注意，名字当中，没有出现 DB 这两个字母)。是的，开源软件界备受瞩目的新星 —— CouchDB 团队已经踏上了全新的旅程，他们正朝着下一个目标进发。我很愿意见到他们取得成功！ 在 CouchDB 狐狸书 中，作者 Jan Lehnardt 描述了一种全新的 Web 开发模式，有这样一句话来形容这种新的开发方式。 CouchDB has changed the way I think about developing web applications 在有着 10+ 年 Web 开发经验的我看来，尤其是在确实理解了他们心目中的开发方式之后，我觉得，这并不是一句阿谀奉承的面子话。而是，实事求是地说 —— 完全没有夸张的成分。 我在这里极其“概略”的介绍一下这种匪夷所思开发方式的若干基本要素： CouchDB 是一个 NO-SQL 的“文档数据库”，以 B-Tree 提供 Powerful 的数据存储与访问能力 [...]]]></description>
			<content:encoded><![CDATA[<p>有关 CouchDB 的最新动向是： Damien Katz 已经离开了 IBM ，他和他的团队，在 200w $ 投资的帮助之下，开始创业。美国投资人的魄力与专业素养，让我这个中国软件人羡慕不已，什么时候我们中国也会出现这种“纯粹谈技术就能够决定是否投你”的投资人呢？新公司名叫 Couch IO (请注意，名字当中，没有出现 DB 这两个字母)。是的，开源软件界备受瞩目的新星 —— CouchDB 团队已经踏上了全新的旅程，他们正朝着下一个目标进发。我很愿意见到他们取得成功！</p>
<p><img src="http://covers.oreilly.com/images/9780596155902/cat.gif" alt="CouchDB 狐狸书" /></p>
<p>在 <a href="http://books.couchdb.org/relax/" target=_blank>CouchDB 狐狸书</a> 中，作者 Jan Lehnardt 描述了一种全新的 Web 开发模式，有这样一句话来形容这种新的开发方式。</p>
<blockquote><p>CouchDB has changed the way I think about developing web applications</p></blockquote>
<p>在有着 10+ 年 Web 开发经验的我看来，尤其是在确实理解了他们心目中的开发方式之后，我觉得，这并不是一句阿谀奉承的面子话。而是，实事求是地说 —— 完全没有夸张的成分。</p>
<p>我在这里极其“概略”的介绍一下这种匪夷所思开发方式的若干基本要素：<br />
<span id="more-675"></span></p>
<ol>
<li>CouchDB 是一个 NO-SQL 的“文档数据库”，以 B-Tree 提供 Powerful 的数据存储与访问能力</li>
<li>CouchDB 是追加型数据库，其内部以 MVCC 机制管理每个文档的不同版本</li>
<li>CouchDB 采用了一种没有中心节点的架构设计，数据可以以数据库为单位，在多个 CouchDB 节点之间互相同步，数据同步时，也用 MVCC 来保证数据同步的一致性</li>
<li>CouchDB 以 Http Restful 的方式对其中存储的文档提供最基本的 CRUD 接口，也就是说能够直接以 Ajax 方式使用这些接口</li>
<li>CouchDB 实现了服务端逻辑的扩展机制，即，可采用 JavaScript (也可以用其他语言)定义 View ，这个 View 会在 Server 端以 Map-Reduce 方式来运行，中间结果也被 B-Tree 保存，当数据变化时，只需重新 Map 此条数据即可保持同步。也就是说，一旦 View 定义好，查询结果就已经准备好了，取用之时，无须计算</li>
<li>上述逻辑扩展机制的“服务端代码”也被储存在一类特殊的文档之中，简而言之，这些“服务端代码”在绝大部分的情况下，都可以被当作“普通数据”来对待，尤其是，同样可以在节点之间同步</li>
<li>文档可以带附件，想带多少带多少，想带什么带什么，随便带，没限制。比方说，Browser 客户端会用到的 HTML、CSS、脚本、图片什么的</li>
</ol>
<p>PS. 上面描述的这些正处在迅速的进化之中……包括身份验证，同步过滤，URL Mapping 等等，所有需要用到的一切，正在迅速被增加进来。</p>
<p>已经呼之欲出 —— CouchDB 将会进化成为一个 AppServer！虽然还处在非常早期的阶段，仍然缺少拼图的一些重要部分，但我们已经可以大致的窥见这头犀利 AppServer 的一些只鳞片爪。</p>
<ul>
<li>服务端脚本 —— 纯 JavaScript 开发环境</li>
<li>特殊文档 —— Web 应用本身就是一个文档</li>
<li>程序同步 —— 一键安装 Web 应用</li>
<li>数据同步 —— 离线 Web 应用</li>
<li>……</li>
</ul>
<p>基于前面提到要素，不难组合出更多妙不可言的特性来，对于日益得到重视的 JavaScript 程序员们而言(实际上，其他程序员也是一样，只是，稍微没有那么“显而易见”而已)，未来是一件多么值得期待的事？</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/couchdb_good_future_to_expect.html/feed</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>素数求解，兼谈Erlang的性能特性</title>
		<link>http://erlang-china.org/study/prime_case-and-erlang_performance.html</link>
		<comments>http://erlang-china.org/study/prime_case-and-erlang_performance.html#comments</comments>
		<pubDate>Tue, 24 Nov 2009 09:55:53 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=625</guid>
		<description><![CDATA[javaeye 的 dachidahu 同学不久前提了一个关于 Erlang 的问题 —— 《Erlang 求解1到N 素数的效率问题》。我试了一下，这个问题并不复杂，但结果相当有趣。对于初学 Erlang 的朋友而言，这个程序作为一个了解 Erlang 语言性能特性的例子，非常具有典型性。因此，特地整理一番，与众初学者共享。 这是“求素数”的 Java 代码。基本来自 dachidahu 的帖子，为了测试方便，略做修改。 &#19979;&#36733;: Prime.java// javac Prime.java// java Prime 1000000public class Prime {&#160;&#160; &#160;public static void main(String[] args){&#160;&#160; &#160; &#160; &#160;int n = Integer.parseInt(args[0]);&#160;&#160; &#160; &#160; &#160;long start = System.currentTimeMillis();&#160;&#160; &#160; &#160; &#160;for(int i=2; i&#60;n; i++){&#160;&#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>javaeye 的 dachidahu 同学不久前提了一个关于 Erlang 的问题 —— 《<a href="http://www.javaeye.com/topic/516877" target=_blank>Erlang 求解1到N 素数的效率问题</a>》。我试了一下，这个问题并不复杂，但结果相当有趣。对于初学 Erlang 的朋友而言，这个程序作为一个了解 Erlang 语言性能特性的例子，非常具有典型性。因此，特地整理一番，与众初学者共享。</p>
<p><span id="more-625"></span></p>
<p>这是“求素数”的 Java 代码。基本来自 dachidahu 的帖子，为了测试方便，略做修改。</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=625&amp;download=Prime.java">Prime.java</a></div><div class="hl-surround"><div class="hl-main"><span style="color: #ffa500;">// javac Prime.java</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">// java Prime 1000000</span><span style="color: Gray;"><br /></span><span style="color: Green;">public</span><span style="color: Gray;"> </span><span style="color: Green;">class</span><span style="color: Gray;"> </span><span style="color: Blue;">Prime</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">public</span><span style="color: Gray;"> </span><span class="hl-types">static</span><span style="color: Gray;"> </span><span class="hl-types">void</span><span style="color: Gray;"> </span><span style="color: Blue;">main</span><span style="color: Olive;">(</span><span style="color: Blue;">String</span><span style="color: Olive;">[]</span><span style="color: Gray;"> </span><span style="color: Blue;">args</span><span style="color: Olive;">){</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="hl-types">int</span><span style="color: Gray;"> </span><span style="color: Blue;">n</span><span style="color: Gray;"> = </span><span style="color: Blue;">Integer</span><span style="color: Gray;">.</span><span style="color: Blue;">parseInt</span><span style="color: Olive;">(</span><span style="color: Blue;">args</span><span style="color: Olive;">[</span><span style="color: Maroon;">0</span><span style="color: Olive;">])</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="hl-types">long</span><span style="color: Gray;"> </span><span style="color: Blue;">start</span><span style="color: Gray;"> = </span><span style="color: Blue;">System</span><span style="color: Gray;">.</span><span style="color: Blue;">currentTimeMillis</span><span style="color: Olive;">()</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span class="hl-types">int</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Gray;">=</span><span style="color: Maroon;">2</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">&lt;</span><span style="color: Blue;">n</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">++</span><span style="color: Olive;">){</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span class="hl-types">boolean</span><span style="color: Gray;"> </span><span style="color: Blue;">b</span><span style="color: Gray;"> = </span><span style="color: Blue;">isPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">i</span><span style="color: Olive;">)</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">// if(b) System.out.println(i);</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Olive;">}</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="hl-types">long</span><span style="color: Gray;"> </span><span style="color: Blue;">now</span><span style="color: Gray;"> = </span><span style="color: Blue;">System</span><span style="color: Gray;">.</span><span style="color: Blue;">currentTimeMillis</span><span style="color: Olive;">()</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">System</span><span style="color: Gray;">.</span><span style="color: Blue;">out</span><span style="color: Gray;">.</span><span style="color: Blue;">println</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">total running time: </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">+</span><span style="color: Olive;">(</span><span style="color: Blue;">now</span><span style="color: Gray;"> - </span><span style="color: Blue;">start</span><span style="color: Olive;">)</span><span style="color: Gray;">+</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;"> ms</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Olive;">}</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">public</span><span style="color: Gray;"> </span><span class="hl-types">static</span><span style="color: Gray;"> </span><span class="hl-types">boolean</span><span style="color: Gray;"> </span><span style="color: Blue;">isPrime</span><span style="color: Olive;">(</span><span class="hl-types">int</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Olive;">){</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span class="hl-types">int</span><span style="color: Gray;"> </span><span style="color: Blue;">j</span><span style="color: Gray;">=</span><span style="color: Maroon;">2</span><span style="color: Gray;">; </span><span style="color: Blue;">j</span><span style="color: Gray;">&lt;=</span><span style="color: Blue;">Math</span><span style="color: Gray;">.</span><span style="color: Blue;">sqrt</span><span style="color: Olive;">(</span><span style="color: Blue;">i</span><span style="color: Olive;">)</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">; </span><span style="color: Blue;">j</span><span style="color: Gray;">++</span><span style="color: Olive;">){</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Blue;">i</span><span style="color: Gray;">%</span><span style="color: Blue;">j</span><span style="color: Gray;"> == </span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Green;">false</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Olive;">}</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Green;">true</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Olive;">}</span><span style="color: Gray;"><br /></span><span style="color: Olive;">}</span></div></div>
<p>这是相应的 Erlang 源代码。顺手写的。实际包含三个分支，略有区别。其中的 a 分支是严格按照 java 版本的逻辑逐行翻译写出来的。 b 和 a 的唯一区别是在递归当中加入了一个列表参数 L 来传递计算结果。c 分支则采用 dachidahu 同学的“优化思路”——用已经求出的素数来作为被除数，以降低运算次数。</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=625&amp;download=prime.erl">prime.erl</a></div><div class="hl-surround"><div class="hl-main"><span style="color: #ffa500;">%% erlc prime.erl</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">%% erlc +native +&quot;{hipe,[o3]}&quot; prime.erl</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">%% erl -eval &quot;prime:start(a, 1000000).&quot; -s c q -noshell</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">%% erl -eval &quot;prime:start(b, 1000000).&quot; -s c q -noshell</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">%% erl -eval &quot;prime:start(c, 1000000).&quot; -s c q -noshell</span><span style="color: Gray;"><br />&nbsp;<br />-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">prime</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;">2</span><span style="color: Olive;">])</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">M</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Blue;">statistics</span><span style="color: Olive;">(</span><span style="color: Blue;">runtime</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Blue;">_L</span><span style="color: Gray;"> = </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">M</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp;{</span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">T</span><span style="color: Gray;">} = </span><span style="color: Blue;">statistics</span><span style="color: Olive;">(</span><span style="color: Blue;">runtime</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">total running time: ~p ms ~n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">T</span><span style="color: Olive;">])</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Blue;">L</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">a</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">_L</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">case</span><span style="color: Gray;"> </span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">trunc</span><span style="color: Olive;">(</span><span style="color: Blue;">math</span><span style="color: Gray;">:</span><span style="color: Blue;">sqrt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">))</span><span style="color: Gray;"> </span><span style="color: Green;">of</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">true</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">a</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">a</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">end</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">b</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">case</span><span style="color: Gray;"> </span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">trunc</span><span style="color: Olive;">(</span><span style="color: Blue;">math</span><span style="color: Gray;">:</span><span style="color: Blue;">sqrt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">))</span><span style="color: Gray;"> </span><span style="color: Green;">of</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Blue;">true</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">b</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Gray;">++</span><span style="color: Olive;">[</span><span style="color: Blue;">X</span><span style="color: Olive;">])</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">b</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">end</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">c</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">case</span><span style="color: Gray;"> </span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Gray;">, </span><span style="color: Blue;">trunc</span><span style="color: Olive;">(</span><span style="color: Blue;">math</span><span style="color: Gray;">:</span><span style="color: Blue;">sqrt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">))</span><span style="color: Gray;"> </span><span style="color: Green;">of</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">true</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">c</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Gray;">++</span><span style="color: Olive;">[</span><span style="color: Blue;">X</span><span style="color: Olive;">])</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">findPrime</span><span style="color: Olive;">(</span><span style="color: Blue;">c</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">end</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">false</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">true</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">E</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">N</span><span style="color: Gray;"> =&lt; </span><span style="color: Blue;">E</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">case</span><span style="color: Gray;"> </span><span style="color: Blue;">X</span><span style="color: Gray;"> </span><span style="color: Blue;">rem</span><span style="color: Gray;"> </span><span style="color: Blue;">N</span><span style="color: Gray;"> </span><span style="color: Green;">of</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Maroon;">0</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">false</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">E</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">end</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeInt</span><span style="color: Olive;">(</span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">true</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">false</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">true</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">H</span><span style="color: Gray;">|</span><span style="color: Blue;">T</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">E</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">H</span><span style="color: Gray;"> =&lt; </span><span style="color: Blue;">E</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">case</span><span style="color: Gray;"> </span><span style="color: Blue;">X</span><span style="color: Gray;"> </span><span style="color: Blue;">rem</span><span style="color: Gray;"> </span><span style="color: Blue;">H</span><span style="color: Gray;"> </span><span style="color: Green;">of</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Maroon;">0</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">false</span><span style="color: Gray;">;<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">T</span><span style="color: Gray;">, </span><span style="color: Blue;">E</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;</span><span style="color: Green;">end</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">isPrimeList</span><span style="color: Olive;">(</span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">true</span><span style="color: Gray;">.</span></div></div>
<p>作为基准，先看 Java 的版本表现如何：</p>
<div class="hl-surround"><div class="hl-main">jackyz@ubuntu:~$ javac Prime.java <br />jackyz@ubuntu:~$ java Prime 1000000<br />total running time: 4323 ms</div></div>
<p>看看 Erlang 三个分支各自的运算表现：</p>
<div class="hl-surround"><div class="hl-main">jackyz@ubuntu:~$ erlc prime.erl<br />jackyz@ubuntu:~$ erl -eval &quot;prime:start(a, 1000000).&quot; -s c q -noshell<br />total running time: 5660 ms<br />jackyz@ubuntu:~$ erl -eval &quot;prime:start(b, 1000000).&quot; -s c q -noshell<br />total running time: 69810 ms<br />jackyz@ubuntu:~$ erl -eval &quot;prime:start(c, 1000000).&quot; -s c q -noshell<br />total running time: 65510 ms</div></div>
<p>结果有没有让你吃惊？</p>
<p>分支 a 与 java 代码几乎是严格对应的，执行的性能比 java 略慢一点(慢30%)，但差别很有限，并没有得出象 dachidahu 同学那样离谱的差异。</p>
<p>分支 b 和分支 a 的唯一区别是多加了一个参数用来传递当前已经算出的素数。仅仅多了这么一步，和前面一个分支相比，立刻就有了非常惊人的差别(慢1133%)。</p>
<p>分支 c 则正如我们预料的一样，要比分支 b 快一点点。但也仅仅只是比 b 快了那么一点点而已(快6%)。</p>
<p>通过这个例子，我们能够体会到 Erlang 怎样的性能特性呢？</p>
<ol>
<li>Erlang 并不以高效著称(它最为突出的特性应该是可靠性，其次是基于消息的彻底隔离与内置的分布式支持)，虽说 Erlang 团队在虚拟机优化上下了很多功夫，但比起同样经过“业界精英苦心优化”的 Java 来说，可能仍然是各有千秋(具体怎么个各有千秋法，仍需仔细考察)。至少在这个例子中 Erlang byte code 并没有在实际执行中表现出超越 Java byte code 的性能。</li>
<li>和上面一条恰好相反，Erlang 的虚拟机也并不像我们所想象的那么糟糕，有文章称 Erlang 虚拟机比 Java 虚拟机要慢上一个数量级，我不知道这样的结论是如何得出的，但至少在上面这个例子中的 rem (整除)操作上，并没有看到这样的差异。</li>
<li>虽说列表操作在 Erlang 语法里看起来只是一句超简单的“原子操作”，但实际上它也是有代价的。尤其是，当需要承载大量数据的时候(有文章称超过 1K 数据量就应该考虑其他数据结构)，就不再适合采用 list 来装数据。</li>
<li>类似于 list 的例子，在 Erlang 里可能还有不少。具体会怎样，应该靠实际而耐心的测试去发现问题，而不是我们的猜测。要点就是，这是不同的语言，之前的经验或许已经不再适用。</li>
<li>不要提前(草率)优化。优化是一个精细活，必须建立在精细设计的 profiling 的基础之上，找出瓶颈，然后再优化之。否则，就会象上面的 c 分支一样，优化了半天，却根本就没有击中要害。</li>
</ol>
<p>我们以一个 trick 来结尾，在 Erlang 里面是否有超越 Java 执行性能的可能呢？有！比如说，我们可以象这样：</p>
<div class="hl-surround"><div class="hl-main">jackyz@ubuntu:~$ erlc +native +&quot;{hipe,[o3]}&quot; prime.erl<br />jackyz@ubuntu:~$ erl -eval &quot;prime:start(a, 1000000).&quot; -s c q -noshell<br />total running time: 3010 ms</div></div>
<p>不错吧。</p>
<p>不过，这是以 native code 对 byte code 的怪招，胜之不武。哈哈。</p>
<p>-EOF-</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/prime_case-and-erlang_performance.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>[荐]Erlang和Python的互通</title>
		<link>http://erlang-china.org/study/erlang_call_python_in_port.html</link>
		<comments>http://erlang-china.org/study/erlang_call_python_in_port.html#comments</comments>
		<pubDate>Wed, 02 Sep 2009 02:48:39 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=594</guid>
		<description><![CDATA[陈皓同学的博客建在 ZDNet 上，他最近正在研究 Erlang ，在官方文档上花了 24 个小时的研读之后，终于调通了 Erlang 通过 Port 机制调用 Python 的代码。或许，他的文章和代码能帮助更多的朋友节约更多的 24 个小时，尤其是对于那些想要写 Port 或正在用 Python 的朋友。故，在此推荐之。地址在［这里］。 其实 Port 对 Erlang 而言是一个很重要的扩展设施。在 Disco，在 CouchDB，在很多重量级的 Erlang 项目中，我们都能看到 Port 的使用。在大量的 Erlang 项目实战中，最初的快速原型开发确定之后，再将发现的瓶颈部分改为更加高效的本地 Port 来实现(如果能够确认这样的实现真的更加高效的话)，这似乎也是比较通行的做法。放在这样的应用场景下考虑，此时的 Port 其实充当着“ Worker 调用者”的角色，而 Erlang 自身则变成了动态机器集群的“粘合系统”。与“将一个机房/一堆机器当作一台机器来使用”的架构目标达成了极佳的重合。 对于大多数的 Erlanger 而言，在实际的工程实践中，对“效率”和“适用性”上的考量应该被放在第一位，对“是否纯粹”的执着则应该被看得更淡一些。]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.zdnet.com.cn/?422032" target=_blank>陈皓同学的博客</a>建在 ZDNet 上，他最近正在研究 Erlang ，在官方文档上花了 24 个小时的研读之后，终于调通了 Erlang 通过 Port 机制调用 Python 的代码。或许，他的文章和代码能帮助更多的朋友节约更多的 24 个小时，尤其是对于那些想要写 Port 或正在用 Python 的朋友。故，在此推荐之。地址在［<a href="http://blog.zdnet.com.cn/html/32/422032-2883073.html" target=_blank>这里</a>］。</p>
<p>其实 Port 对 Erlang 而言是一个很重要的扩展设施。在 Disco，在 CouchDB，在很多重量级的 Erlang 项目中，我们都能看到 Port 的使用。在大量的 Erlang 项目实战中，最初的快速原型开发确定之后，再将发现的瓶颈部分改为更加高效的本地 Port 来实现(如果能够确认这样的实现真的更加高效的话)，这似乎也是比较通行的做法。放在这样的应用场景下考虑，此时的 Port 其实充当着“ Worker 调用者”的角色，而 Erlang 自身则变成了动态机器集群的“粘合系统”。与“将一个机房/一堆机器当作一台机器来使用”的架构目标达成了极佳的重合。</p>
<p>对于大多数的 Erlanger 而言，在实际的工程实践中，对“效率”和“适用性”上的考量应该被放在第一位，对“是否纯粹”的执着则应该被看得更淡一些。</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/erlang_call_python_in_port.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<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>
		<item>
		<title>[转]Erlang的类型系统和静态分析</title>
		<link>http://erlang-china.org/study/erlang_type_and_dialyzer.html</link>
		<comments>http://erlang-china.org/study/erlang_type_and_dialyzer.html#comments</comments>
		<pubDate>Tue, 09 Jun 2009 02:31:07 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>
		<category><![CDATA[dialyzer]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[guide]]></category>
		<category><![CDATA[type]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=523</guid>
		<description><![CDATA[转载说明 “Erlang 是动态类型的语言，因而不能进行静态分析，所生成的文档也不包含有助于理解的类型信息”——这是惯常的看法，广为流行，而且被看作是 Erlang 在开发大型系统时的一个短板(大型系统意味着更强烈的静态分析需求和更严重的依赖文档进行沟通)。 然而 Erlang 是一个有着 20 多年历史的成熟系统，它早已发展出了一套自己的类型标注系统，不仅用来生成文档，更重要的是可以据此对源码进行静态分析，通过程序来排除一些低级的和隐藏的错误。在这方面， Erlang OTP 的源码本身及其文档就是最好的例子。在 《Erlang 程序设计》 的附录A部分，对于这个系统的使用已经进行了充分的说明。 需要强调的一点是在 Erlang 语言的背后还有一个活跃的社区(后者更为重要)，其 EPP 过程一直都在持续不断地推进语言本身的进化。这方面最新的成果便是：在 R13 中，将此前文档级的 @spec，@type 标注升级为语言级的 -spec，-type 标注。可以预期的一点是，在未来的版本中，这些方面仍将持续推进。 litaocheng 同学的这篇“Erlang类型及函数声明规格”，风格严谨，论述详尽，涵盖了最新的语言特性，是任何一个程序员想要开发“严肃 Erlang 程序”的必读文档。 Erlang类型及函数声明规格 Author: litaocheng Mail: litaocheng@gmail.com Date: 2009.6.8 Copyright: This document has been placed in the public domain. Contents: 概述 意义 规范 类型及其定义语法 自定义类型定义 在record中使用类型声明 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>转载说明</strong></p>
<p>“Erlang 是动态类型的语言，因而不能进行静态分析，所生成的文档也不包含有助于理解的类型信息”——这是惯常的看法，广为流行，而且被看作是 Erlang 在开发大型系统时的一个短板(大型系统意味着更强烈的静态分析需求和更严重的依赖文档进行沟通)。</p>
<p>然而 Erlang 是一个有着 20 多年历史的成熟系统，它早已发展出了一套自己的类型标注系统，不仅用来生成文档，更重要的是可以据此对源码进行静态分析，通过程序来排除一些低级的和隐藏的错误。在这方面， Erlang OTP 的源码本身及其文档就是最好的例子。在 《Erlang 程序设计》 的附录A部分，对于这个系统的使用已经进行了充分的说明。</p>
<p>需要强调的一点是在 Erlang 语言的背后还有一个活跃的社区(后者更为重要)，其 EPP 过程一直都在持续不断地推进语言本身的进化。这方面最新的成果便是：在 R13 中，将此前文档级的 @spec，@type 标注升级为语言级的 -spec，-type 标注。可以预期的一点是，在未来的版本中，这些方面仍将持续推进。</p>
<p>litaocheng 同学的这篇“Erlang类型及函数声明规格”，风格严谨，论述详尽，涵盖了最新的语言特性，是任何一个程序员想要开发“严肃 Erlang 程序”的必读文档。</p>
<p><span id="more-523"></span></p>
<p><strong>Erlang类型及函数声明规格</strong></p>
<p>Author: 	litaocheng<br />
Mail: 	litaocheng@gmail.com<br />
Date: 	2009.6.8<br />
Copyright: 	This document has been placed in the public domain.<br />
Contents:<br />
<code></p>
<ul>
<li>概述</li>
<li>意义</li>
<li>规范
<ul>
<li>类型及其定义语法</li>
<li>自定义类型定义</li>
<li>在record中使用类型声明</li>
<li>函数规范定义</li>
</ul>
</li>
<li>使用dialyzer进行静态分析
<ul>
<li>生成plt</li>
<li>使用dialyzer分析</li>
</ul>
</li>
<li>参考</li>
</ul>
<p><strong>概述</strong></p>
<p>Erlang为动态语言，变量在运行时动态绑定，这对于我们获取函数的参数及返回值的类型信息具有一定的难度。为了弥补这个不足，在Erlang中我们可以通过type及spec定义数据类型及函数原型。通过这些信息，我们对函数及调用进行静态检测，从而发现一些代码中问题。同时，这些信息也便于他人了解函数接口，也可以用来生成文档。</p>
<p><strong>意义</strong></p>
<ul>
<li>定义各种自定义数据类型</li>
<li>定义函数的参数及返回值</li>
<li>dialyzer 进行代码静态分析</li>
<li>edoc利用这些信息生成文档</li>
</ul>
<p><strong>规范</strong></p>
<p><strong>类型及其定义语法</strong></p>
<p>数据类型由一系列Erlang terms组成，其有各种基本数据类型组成(如 integer() , atom() , pid() ）。Erlang预定义数据类型代表属于此类型的所有数据，比如 atom() 代表所有的atom类型的数据。</p>
<p>数据类型，由基本数据类型及其他自定义数据类型组成，其范围为对应数据类型的合集。比如:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">atom</span><span style="color: Olive;">()</span><span style="color: Gray;"> | </span><span style="color: #8b0000;">'</span><span style="color: Red;">bar</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> | </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span><span style="color: Gray;"> | </span><span style="color: Maroon;">42</span></div></div>
<p>与:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">atom</span><span style="color: Olive;">()</span><span style="color: Gray;"> | </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span></div></div>
<p>具有相同的含义。</p>
<p>各种类型之间具有一定的层级关系，其中最顶层的 any() 可以代表任何Erlang类型，而最底层的 none() 表示空的数据类型。</p>
<p>预定义的类型及语法如下:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">Type</span><span style="color: Gray;"> :: </span><span style="color: Blue;">any</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% 最顶层类型，表示任意的Erlang term</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">none</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% 最底层类型，不包含任何term</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">pid</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">port</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">ref</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Olive;">[]</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% nil</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Atom</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Binary</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">float</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Fun</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Integer</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">List</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Tuple</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Union</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">UserDefined</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% described in Section 2</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Union</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;"> | </span><span style="color: Blue;">Type2</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Atom</span><span style="color: Gray;"> :: </span><span style="color: Blue;">atom</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">Erlang_Atom</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% 'foo', 'bar', ...</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Binary</span><span style="color: Gray;"> :: </span><span style="color: Blue;">binary</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% &lt;&lt;_:_ * 8&gt;&gt;</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; | </span><span style="color: Olive;">&lt;&lt;&gt;&gt;</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; | </span><span style="color: Olive;">&lt;&lt;</span><span style="color: Blue;">_</span><span style="color: Gray;">:</span><span style="color: Blue;">Erlang_Integer</span><span style="color: Olive;">&gt;&gt;</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% Base size</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; | </span><span style="color: Olive;">&lt;&lt;</span><span style="color: Blue;">_</span><span style="color: Gray;">:</span><span style="color: Blue;">_</span><span style="color: Gray;">*</span><span style="color: Blue;">Erlang_Integer</span><span style="color: Olive;">&gt;&gt;</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% Unit size</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; | </span><span style="color: Olive;">&lt;&lt;</span><span style="color: Blue;">_</span><span style="color: Gray;">:</span><span style="color: Blue;">Erlang_Integer</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">:</span><span style="color: Blue;">_</span><span style="color: Gray;">*</span><span style="color: Blue;">Erlang_Integer</span><span style="color: Olive;">&gt;&gt;</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Fun</span><span style="color: Gray;"> :: </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% 任意函数</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;| </span><span style="color: Green;">fun</span><span style="color: Olive;">((</span><span style="color: Gray;">...</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">Type</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% 任意arity, 只定义返回类型</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;| </span><span style="color: Green;">fun</span><span style="color: Olive;">(()</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">Type</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp;| </span><span style="color: Green;">fun</span><span style="color: Olive;">((</span><span style="color: Blue;">TList</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">Type</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Integer</span><span style="color: Gray;"> :: </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;| </span><span style="color: Blue;">Erlang_Integer</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% ..., -1, 0, 1, ... 42 ...</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;| </span><span style="color: Blue;">Erlang_Integer</span><span style="color: Gray;">..</span><span style="color: Blue;">Erlang_Integer</span><span style="color: Gray;"> </span><span style="color: #ffa500;">%% 定义一个整数区间</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">List</span><span style="color: Gray;"> :: </span><span style="color: Blue;">list</span><span style="color: Olive;">(</span><span style="color: Blue;">Type</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% 格式规范的list (以[]结尾)</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">improper_list</span><span style="color: Olive;">(</span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">Type2</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #ffa500;">%% Type1=contents, Type2=termination</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; | </span><span style="color: Blue;">maybe_improper_list</span><span style="color: Olive;">(</span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">Type2</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">%% Type1 and Type2 as above</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">Tuple</span><span style="color: Gray;"> :: </span><span style="color: Blue;">tuple</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% 表示包含任意元素的tuple</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp;| {}<br />&nbsp;&nbsp; &nbsp; &nbsp;| {</span><span style="color: Blue;">TList</span><span style="color: Gray;">}<br />&nbsp;<br /></span><span style="color: Blue;">TList</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp;| </span><span style="color: Blue;">Type</span><span style="color: Gray;">, </span><span style="color: Blue;">TList</span></div></div>
<p>由于 lists 经常使用，我们可以将 list(T) 简写为 [T] ，而 [T, ...] 表示一个非空的元素类型为T的规范列表。两者的区别是 [T] 可能为空，而 [T, ...] 至少包含一个元素。</p>
<p>'_' 可以用来表示任意类型。</p>
<p>请注意, list()表示任意类型的list，其等同于 [_]或[any()], 而 [] ，仅仅表示一个单独的类型即空列表。</p>
<p>为了方便，下面是一个内建类型列表</p>
<table>
<thead>
<tr>
<th class="head">Built-in type</th>
<th class="head">Stands for</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<tt class="docutils literal"><span class="pre">term()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">any()</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">bool()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">'false'</span><br />
 <span class="pre">|</span><br />
 <span class="pre">'true'</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">byte()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">0..255</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">char()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">0..16#10ffff</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">non_neg_integer()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">0..</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">pos_integer()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">1..</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">neg_integer()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">..-1</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">number()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">integer()</span><br />
 <span class="pre">|</span><br />
 <span class="pre">float()</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">list()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">[any()]</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">maybe_improper_list()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">maybe_improper_list(any(),</span><br />
 <span class="pre">any())</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">maybe_improper_list(T)</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">maybe_improper_list(T,</span><br />
 <span class="pre">any())</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">string()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">[char()]</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">nonempty_string()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">[char(),...]</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">iolist()</span><br />
</tt>
</td>
<td>
<dl class="first last docutils">
<dt>
<tt class="docutils literal"><span class="pre">maybe_improper_list(</span><br />
</tt>
</dt>
<dd>
<tt class="docutils literal"><span class="pre">char()</span><br />
 <span class="pre">|</span><br />
 <span class="pre">binary()</span><br />
 <span class="pre">|</span><br />
</tt><br />
<tt class="docutils literal"><span class="pre">iolist(),</span><br />
 <span class="pre">binary()</span><br />
 <span class="pre">|</span><br />
 <span class="pre">[])</span><br />
</tt>
</dd>
</dl>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">module()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">atom()</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">mfa()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">{atom(),atom(),byte()}</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">node()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">atom()</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">timeout()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">'infinity'</span><br />
 <span class="pre">|</span><br />
 <span class="pre">non_neg_integer()</span><br />
</tt>
</td>
</tr>
<tr>
<td>
<tt class="docutils literal"><span class="pre">no_return()</span><br />
</tt>
</td>
<td>
<tt class="docutils literal"><span class="pre">none()</span><br />
</tt>
</td>
</tr>
</tbody>
</table>
<p>类型定义不可重名，编译器可以进行检测。(转载注：在R13，如果采用 -type 和 -spec 标注，编译阶段会进行这种检测，然而，因为标注仍然是可选的，所以，如果没有使用标注，则不会进行检测。)</p>
<p>注意 : 还存在一些其他 lists 相关的内建类型，但是因为其名字较长，我们很少使用:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">nonempty_maybe_improper_list</span><span style="color: Olive;">(</span><span style="color: Blue;">Type</span><span style="color: Olive;">)</span><span style="color: Gray;"> :: </span><span style="color: Blue;">nonempty_maybe_improper_list</span><span style="color: Olive;">(</span><span style="color: Blue;">Type</span><span style="color: Gray;">, </span><span style="color: Blue;">any</span><span style="color: Olive;">())</span><span style="color: Gray;"><br /></span><span style="color: Blue;">nonempty_maybe_improper_list</span><span style="color: Olive;">()</span><span style="color: Gray;"> :: </span><span style="color: Blue;">nonempty_maybe_improper_list</span><span style="color: Olive;">(</span><span style="color: Blue;">any</span><span style="color: Olive;">())</span></div></div>
<p>我们也可以使用record标记法来表示数据类型:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">Record</span><span style="color: Gray;"> :: #</span><span style="color: Blue;">Erlang_Atom</span><span style="color: Gray;">{}<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;| #</span><span style="color: Blue;">Erlang_Atom</span><span style="color: Gray;">{</span><span style="color: Blue;">Fields</span><span style="color: Gray;">}</span></div></div>
<p>当前R13B中，已经支持record定义中的类型说明</p>
<p><strong>自定义类型定义</strong></p>
<p>通过前一章节的介绍，我们知道基本的类型语法为一个atom紧随一对圆括号。如果我们想第一个一个新类型，需要使用 'type' 关键字:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">type</span><span style="color: Gray;"> </span><span style="color: Blue;">my_type</span><span style="color: Olive;">()</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type</span><span style="color: Gray;">.</span></div></div>
<p>my_type为我们自定义的type名称，其必须为atom，Type为先前章节介绍的各种类型，其可以为内建类型定义，也可以为可见的（已经定义的）自定义数据类型。否则会编译时保错。</p>
<p>这样递归的类型定义，当前还不支持。</p>
<p>类型定义也可以参数化，我们可以在括号中包含类型，如同Erlang中变量定义，这个参数必须以大写字母开头，一个简单的例子:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">type</span><span style="color: Gray;"> </span><span style="color: Blue;">orddict</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">Val</span><span style="color: Olive;">)</span><span style="color: Gray;"> :: </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">Val</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span></div></div>
<p><strong>在record中使用类型声明</strong></p>
<p>我们可以指定record中字段的类型，语法如下:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>如果字段没有指明类型声明，那么默认为 any() . 比如，上面的record定义与此相同:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;"> :: </span><span style="color: Blue;">any</span><span style="color: Olive;">()</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>如果我们在定义record的时候，指明了初始值，类型声明必须位于初始值之后:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> = </span><span style="color: Olive;">[]</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> = </span><span style="color: Maroon;">42</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">$</span></div></div>
<p>我们可以指定record中字段的类型，语法如下::</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>如果字段没有指明类型声明，那么默认为 any() . 比如，上面的record定义与此相同:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;"> :: </span><span style="color: Blue;">any</span><span style="color: Olive;">()</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>如果我们在定义record的时候，指明了初始值，类型声明必须位于初始值之后:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">field1</span><span style="color: Gray;"> = </span><span style="color: Olive;">[]</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, </span><span style="color: Blue;">field2</span><span style="color: Gray;">, </span><span style="color: Blue;">field3</span><span style="color: Gray;"> = </span><span style="color: Maroon;">42</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type3</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>如果初始值类型与字段的类型声明不一致，会产生一个编译期错误。 filed的默认值为 'undefined' ，因此下面的来个record定义效果相同:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">f1</span><span style="color: Gray;"> = </span><span style="color: Maroon;">42</span><span style="color: Gray;"> :: </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">f2</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; :: </span><span style="color: Blue;">float</span><span style="color: Olive;">()</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">f3</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; :: </span><span style="color: #8b0000;">'</span><span style="color: Red;">a</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> | </span><span style="color: #8b0000;">'</span><span style="color: Red;">b</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br />-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">rec</span><span style="color: Gray;">, {</span><span style="color: Blue;">f1</span><span style="color: Gray;"> = </span><span style="color: Maroon;">42</span><span style="color: Gray;"> :: </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">f2</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; :: </span><span style="color: #8b0000;">'</span><span style="color: Red;">undefined</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> | </span><span style="color: Blue;">float</span><span style="color: Olive;">()</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: Blue;">f3</span><span style="color: Gray;">&nbsp; &nbsp; &nbsp; :: </span><span style="color: #8b0000;">'</span><span style="color: Red;">undefined</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> | </span><span style="color: #8b0000;">'</span><span style="color: Red;">a</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> | </span><span style="color: #8b0000;">'</span><span style="color: Red;">b</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>所以，推荐您在定义record时，指明初始值。</p>
<p>record定义后，我们可以作为一个类型来使用，其用法如下:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">#</span><span style="color: Blue;">rec</span><span style="color: Gray;">{}</span></div></div>
<p>在使用recored类型时，我们也可以重新指定某个field的类型:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">#</span><span style="color: Blue;">rec</span><span style="color: Gray;">{</span><span style="color: Blue;">some_field</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type</span><span style="color: Gray;">}</span></div></div>
<p>没有指明的filed，类型与record定义时指明的类型相同。</p>
<p><strong>函数规范定义</strong></p>
<p>函数规范可以通过新引入的关键字 'spec' 来定义（摒弃了旧的 @spec 声明)。其语法如下:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">Module</span><span style="color: Gray;">:</span><span style="color: Blue;">Function</span><span style="color: Olive;">(</span><span style="color: Blue;">ArgType1</span><span style="color: Gray;">, ..., </span><span style="color: Blue;">ArgTypeN</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">ReturnType</span><span style="color: Gray;">.</span></div></div>
<p>函数的参数数目必须与函数规范定义相同，否则编译出错。</p>
<p>在同一个module内部，可以简化为:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">Function</span><span style="color: Olive;">(</span><span style="color: Blue;">ArgType1</span><span style="color: Gray;">, ..., </span><span style="color: Blue;">ArgTypeN</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">ReturnType</span><span style="color: Gray;">.</span></div></div>
<p>同时，为了便于我们生成文档，我们可以指明参数的名称:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">Function</span><span style="color: Olive;">(</span><span style="color: Blue;">ArgName1</span><span style="color: Gray;"> :: </span><span style="color: Blue;">Type1</span><span style="color: Gray;">, ..., </span><span style="color: Blue;">ArgNameN</span><span style="color: Gray;"> :: </span><span style="color: Blue;">TypeN</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">RT</span><span style="color: Gray;">.</span></div></div>
<p>函数的spec声明可以重载。通过 ';' 来实现:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">foo</span><span style="color: Olive;">(</span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">())</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; </span><span style="color: Olive;">(</span><span style="color: Blue;">integer</span><span style="color: Olive;">())</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">integer</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span></div></div>
<p>我们可以通过spec指明函数的输入和输出的某些关系:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">id</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">X</span><span style="color: Gray;">.</span></div></div>
<p>但是，对于上面的spec，其对输入输出没有任何限定。我们可以对返回值增加一些类似guard的限定:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">id</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">X</span><span style="color: Gray;"> </span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_subtype</span><span style="color: Olive;">(</span><span style="color: Blue;">X</span><span style="color: Gray;">, </span><span style="color: Blue;">tuple</span><span style="color: Olive;">())</span><span style="color: Gray;">.</span></div></div>
<p>其表示X为一个tuple类型。目前仅仅支持 is_subtype 是唯一支持的guard。</p>
<p>某些情况下，有些函数是server的主循环，或者忽略返回值，仅仅抛出某个异常，我们可以使用 no_return() 作为返回值类型:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">my_error</span><span style="color: Olive;">(</span><span style="color: Blue;">term</span><span style="color: Olive;">())</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">no_return</span><span style="color: Olive;">()</span><span style="color: Gray;">.<br /></span><span style="color: Blue;">my_error</span><span style="color: Olive;">(</span><span style="color: Blue;">Err</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">erlang</span><span style="color: Gray;">:</span><span style="color: Blue;">throw</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">error</span><span style="color: Gray;">, </span><span style="color: Blue;">Err</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p><strong>使用dialyzer进行静态分析</strong></p>
<p>我们定义了type及spec，我们可以使用 dialyzer 对代码进行静态分析，在运行之前发现很多低级或者隐藏的错误。</p>
<p><strong>生成plt</strong></p>
<p>为了分析我们的app或者module，我们可以生成一个plt文件（Persistent Lookup Table），其目的是为了加速我们的代码分析过程，plt内部很多类型及函数信息。</p>
<p>首先我们生成一个常用的plt文件, 其包含了以下lib：erts, kernel, stdlib, mnesia, crypto, sasl， ERL_TOP为erlang的安装目录，各个lib因为erlang版本不同会有所差别，我当前使用R13B(erl 5.7.1):</p>
<div class="hl-surround"><div class="hl-main">dialyzer --build_plt -r $ERL_TOP/lib/erts-5.7.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ERL_TOP/lib/kernel-2.13.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ERL_TOP/lib/stdlib-1.16.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ERL_TOP/lib/mnesia-4.4.9/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ERL_TOP/lib/crypto-1.6/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ERL_TOP/lib/sasl-2.1.6/ebin</div></div>
<p>经过十几分钟的的等待，生成了一个~/.dialyzer_plt文件，在生成plt时，可以通过--output_plt 指定生成的plt的名称。</p>
<p>我们也可以随时通过: dialyzer --add_to_plt --plt ~/.dialyzer_plt -c path_to_app 添加应用到既有plt中，也可以通过: dialyzer --remove_from_plt --plt ~/.dialyzer_plt -c path_to_app 从已有plt中删除某个应用。</p>
<p>例子:</p>
<div class="hl-surround"><div class="hl-main">% 生成plt<br />dialyzer --build_plt -r /usr/local/lib/erlang/lib/erts-5.7.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /usr/local/lib/erlang/lib/kernel-2.13.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /usr/local/lib/erlang/lib/stdlib-1.16.1/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /usr/local/lib/erlang/lib/mnesia-4.4.9/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /usr/local/lib/erlang/lib/crypto-1.6/ebin \<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /usr/local/lib/erlang/lib/sasl-2.1.6/ebin<br /><br />% 从plt中去处crypto应用<br />dialyzer --remove_from_plt --plt ~/.dialyzer_plt -c /usr/local/lib/erlang/lib/crypto-1.6/ebin<br /><br />% 向plt中添加crypto应用<br />dialyzer --add_to_plt --plt ~/.dialyzer_plt -c /usr/local/lib/erlang/lib/crypto-1.6/ebin</div></div>
<p><strong>使用dialyzer分析</strong></p>
<p>生成plt后，就可以对我们书写的应用进行静态检查了。</p>
<p>假设我们书写一个简单的module（spec/spec.erl):</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;">spec</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />-</span><span style="color: Blue;">compile</span><span style="color: Olive;">([</span><span style="color: Blue;">export_all</span><span style="color: Olive;">])</span><span style="color: Gray;">.<br />-</span><span style="color: Blue;">vsn</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">0.1</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br />-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">index</span><span style="color: Olive;">(</span><span style="color: Blue;">any</span><span style="color: Olive;">()</span><span style="color: Gray;">, </span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">()</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">any</span><span style="color: Olive;">()])</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">non_neg_integer</span><span style="color: Olive;">()</span><span style="color: Gray;">.<br /></span><span style="color: Blue;">index</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">TupleList</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; </span><span style="color: Blue;">index4</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">TupleList</span><span style="color: Gray;">, </span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">index4</span><span style="color: Olive;">(</span><span style="color: Blue;">_Key</span><span style="color: Gray;">, </span><span style="color: Blue;">_N</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Blue;">_Index</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Maroon;">0</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">index4</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">H</span><span style="color: Gray;"> | </span><span style="color: Blue;">_R</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">Index</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">element</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">H</span><span style="color: Olive;">)</span><span style="color: Gray;"> =:= </span><span style="color: Blue;">Key</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">Index</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">index4</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">_H</span><span style="color: Gray;"> | </span><span style="color: Blue;">R</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">Index</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">index4</span><span style="color: Olive;">(</span><span style="color: Blue;">Key</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">R</span><span style="color: Gray;">, </span><span style="color: Blue;">Index</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: #ffa500;">% correct:</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">%-spec fa( non_neg_integer() ) -&gt; pos_integer().</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;">% invalid:</span><span style="color: Gray;"><br />-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">N</span><span style="color: Gray;"> :: </span><span style="color: Blue;">atom</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">()</span><span style="color: Gray;">.<br /></span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Maroon;">1</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Maroon;">1</span><span style="color: Gray;">;<br /></span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;">-</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;"> + </span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;">-</span><span style="color: Maroon;">2</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br />-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">some_fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">any</span><span style="color: Olive;">()</span><span style="color: Gray;">.<br /></span><span style="color: Blue;">some_fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;<br />&nbsp;&nbsp; </span><span style="color: Blue;">L</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: Blue;">bar</span><span style="color: Gray;">, </span><span style="color: Maroon;">23</span><span style="color: Gray;">}, {</span><span style="color: Blue;">foo</span><span style="color: Gray;">, </span><span style="color: Maroon;">33</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,<br />&nbsp;&nbsp; </span><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">keydelete</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">foo</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>编译spec.erl:</p>
<div class="hl-surround"><div class="hl-main">erlc +debug_info spec.erl</div></div>
<p>使用dialyzer进行分析:</p>
<div class="hl-surround"><div class="hl-main">dialyzer -r ./spec</div></div>
<p>显示结果:</p>
<div class="hl-surround"><div class="hl-main">Checking whether the PLT /home/litao/.dialyzer_plt is up-to-date... yes<br />Proceeding with analysis...<br />spec.erl:15: Invalid type specification for function 'spec':fa/1. The success typing is (non_neg_integer()) -&gt; pos_integer()<br />spec.erl:22: Function some_fun/0 has no local return<br />spec.erl:24: The call lists:keydelete(1,'foo',L::[{'bar',23} | {'foo',33},...]) will never return since it differs in argument position 2 from the success typing arguments: (any(),pos_integer(),maybe_improper_list())<br />done in 0m0.29s<br />done (warnings were emitted)</div></div>
<p>我们可以看到,我们的fa/1函数的spec信息错误，我们进行修正:</p>
<p>由</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">non_neg_integer</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span></div></div>
<p>改为:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Gray;">-</span><span style="color: Blue;">spec</span><span style="color: Gray;"> </span><span style="color: Blue;">fa</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">N</span><span style="color: Gray;"> :: </span><span style="color: Blue;">atom</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">pos_integer</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span></div></div>
<p>some_fun中，lists:keydelete/3参数顺序进行修改:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">keydelete</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">foo</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>改为:</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">keydelete</span><span style="color: Olive;">(</span><span style="color: Blue;">foo</span><span style="color: Gray;">,</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">L</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></div></div>
<p>重新编译，进行dialyzer分析，提示成功:</p>
<div class="hl-surround"><div class="hl-main">litao@litao:~/erltest$ dialyzer -r ./spec<br />Checking whether the PLT /home/litao/.dialyzer_plt is up-to-date... yes<br />Proceeding with analysis... done in 0m0.28s<br />done (passed successfully)</div></div>
<p><strong>参考</strong></p>
<p>[1] 	EEP 8,Types and function specifications (<a href="http://www.erlang.org/eeps/eep-0008.html" target=_blank>http://www.erlang.org/eeps/eep-0008.html</a>)<br />
[2] 	reRestructureText (<a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html" target=_blank>http://docutils.sourceforge.net/docs/user/rst/quickref.html</a>)<br />
[3] 	dialyzer (<a href="http://www.erlang.org/doc/man/dialyzer.html" target=_blank>http://www.erlang.org/doc/man/dialyzer.html</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/erlang_type_and_dialyzer.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[转] couchdb 上手指南</title>
		<link>http://erlang-china.org/study/couchdb-guide.html</link>
		<comments>http://erlang-china.org/study/couchdb-guide.html#comments</comments>
		<pubDate>Wed, 06 May 2009 08:59:39 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=487</guid>
		<description><![CDATA[张沈鹏同学写了一篇不错的 couchdb 上手指南，以 wiki 格式发在 erlang-china 的 maillist 里。这里整理了一下格式，原文转贴出来，并郑重推荐之。 启动 balin couchdb #&#160; ./utils/run 参数有 -h display a short help message and exit -V display version information and exit -a FILE add configuration FILE to chain -A DIR add configuration DIR to chain -n reset configuration file chain (including system default) -c print configuration file [...]]]></description>
			<content:encoded><![CDATA[<p>张沈鹏同学写了一篇不错的 couchdb 上手指南，以 wiki 格式发在 erlang-china 的 maillist 里。这里整理了一下格式，原文转贴出来，并郑重推荐之。</p>
<p><strong>启动</strong></p>
<div class="hl-surround"><div class="hl-main">balin couchdb #&nbsp; ./utils/run</div></div>
<p>参数有</p>
<blockquote><p>
 -h          display a short help message and exit<br />
 -V          display version information and exit<br />
 -a FILE     add configuration FILE to chain<br />
 -A DIR      add configuration DIR to chain<br />
 -n          reset configuration file chain (including system default)<br />
 -c          print configuration file chain and exit<br />
 -i          use the interactive Erlang shell<br />
 -b          spawn as a background process(作为后台进程)<br />
 -p FILE     set the background PID FILE (overrides system default)<br />
 -r SECONDS  respawn background process after SECONDS (defaults to no respawn)<br />
 -o FILE     redirect background stdout to FILE (defaults to $STDOUT_FILE)<br />
 -e FILE     redirect background stderr to FILE (defaults to $STDERR_FILE)<br />
 -s          display the status of the background process<br />
 -k          kill the background process, will respawn if needed<br />
 -d          shutdown the background process(关闭)
</p></blockquote>
<p><strong>配置</strong></p>
<div class="hl-surround"><div class="hl-main">balin couchdb # vi etc/couchdb/local_dev.ini</div></div>
<p>可以指定端口号等，常用的有：</p>
<blockquote><p>
[httpd]<br />
port = 12345<br />
bind_address = 0.0.0.0</p>
<p>[admins]<br />
用户名 = 密码
</p></blockquote>
<p><strong>使用</strong></p>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/_utils/</div></div>
<p>可以创建数据库</p>
<p><strong>python 中的使用</strong></p>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/_utils/database.html?python-tests</div></div>
<p>以操纵这个数据库作为演示,python库有几个函数比如update([...])不能用,不能用用户名密码等等,也许要修一下&#8230;</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Green;">from</span><span style="color: Gray;"> </span><span style="color: Blue;">couchdb</span><span style="color: Gray;"> </span><span style="color: Green;">import</span><span style="color: Gray;"> </span><span style="color: Blue;">client</span><span style="color: Gray;"><br /></span><span style="color: Green;">from</span><span style="color: Gray;"> </span><span style="color: Blue;">couchdb</span><span style="color: Gray;">.</span><span style="color: Blue;">client</span><span style="color: Gray;"> </span><span style="color: Green;">import</span><span style="color: Gray;"> </span><span style="color: Blue;">Document</span><span style="color: Gray;"><br /></span><span style="color: Blue;">server</span><span style="color: Gray;"> = </span><span style="color: Blue;">client</span><span style="color: Gray;">.</span><span style="color: Blue;">Server</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">http://123.123.123.123:12345/</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#打开数据库</span><span style="color: Gray;"><br /></span><span style="color: Blue;">db</span><span style="color: Gray;"> = </span><span style="color: Blue;">server</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">python-tests</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#创建一条数据</span><span style="color: Gray;"><br /></span><span style="color: Blue;">doc_id</span><span style="color: Gray;"> = </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">create</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: #8b0000;">'</span><span style="color: Red;">type</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: #8b0000;">'</span><span style="color: Red;">Person</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: #8b0000;">'</span><span style="color: Red;">name</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: #8b0000;">'</span><span style="color: Red;">John Doe</span><span style="color: #8b0000;">'</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#获取一条数据,这个doc接口和字典一样</span><span style="color: Gray;"><br /></span><span style="color: Blue;">doc</span><span style="color: Gray;"> = </span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: Blue;">doc_id</span><span style="color: Olive;">]</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#_rev是版本,_id是uuid</span><span style="color: Gray;"><br /></span><span style="color: Blue;">doc</span><span style="color: Gray;">.</span><span style="color: Blue;">items</span><span style="color: Olive;">()</span><span style="color: Gray;"><br /></span><span style="color: Olive;">[(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">_rev</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">1-2963977070</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">_id</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">4a36f238f4facbe08762b1a958cef39e</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">type</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">Person</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">name</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">John Doe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)]</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#可以自己指定主键</span><span style="color: Gray;"><br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"> = {</span><span style="color: #8b0000;">'</span><span style="color: Red;">type</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: #8b0000;">'</span><span style="color: Red;">person</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: #8b0000;">'</span><span style="color: Red;">name</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: #8b0000;">'</span><span style="color: Red;">John Doe</span><span style="color: #8b0000;">'</span><span style="color: Gray;">}<br />&nbsp;<br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span><span style="color: Blue;">items</span><span style="color: Olive;">()</span><span style="color: Gray;"><br /></span><span style="color: Olive;">[(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">_rev</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">1-2744716443</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">_id</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">type</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">person</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">,<br /></span><span style="color: Olive;">(</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">name</span><span style="color: #8b0000;">'</span><span style="color: Gray;">, </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">John Doe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)]</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#更新</span><span style="color: Gray;"><br /></span><span style="color: Blue;">badman</span><span style="color: Gray;"> = </span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"><br /></span><span style="color: Blue;">badman</span><span style="color: Olive;">[</span><span style="color: Blue;">age</span><span style="color: Olive;">]</span><span style="color: Gray;">=</span><span style="color: Maroon;">1234</span><span style="color: Gray;"><br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">badman</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#删除,可以用db.delete(doc)来删除</span><span style="color: Gray;"><br /></span><span style="color: Green;">del</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">JohnDoe</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#遍历</span><span style="color: Gray;"><br /></span><span style="color: Green;">for</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">view</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">_all_docs</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">:<br />&nbsp;&nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;">.</span><span style="color: Blue;">id</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: #ffa500;">#看数据库信息</span><span style="color: Gray;"><br /></span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">info</span><span style="color: Olive;">()</span><span style="color: Gray;"><br />{</span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">compact_running</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Green;">False</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">db_name</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">python-tests</span><span style="color: #8b0000;">'</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">disk_size</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Maroon;">24381</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">doc_count</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Maroon;">13</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">doc_del_count</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Maroon;">0</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">instance_start_time</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">1241518867280531</span><span style="color: #8b0000;">'</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">purge_seq</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Maroon;">0</span><span style="color: Gray;">,<br /></span><span style="color: Blue;">u</span><span style="color: #8b0000;">'</span><span style="color: Red;">update_seq</span><span style="color: #8b0000;">'</span><span style="color: Gray;">: </span><span style="color: Maroon;">21</span><span style="color: Gray;">}<br />&nbsp;<br /></span><span style="color: #ffa500;">#文档可以有2进制的附件 put_attachment 用这个函数上传</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;"># 查询,map_fun是一个js函数,emit是emit(key,value)。key,value均可是null</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;"># web页面上有Select view查询,可以直接搜索测试</span><span style="color: Gray;"><br /></span><span style="color: #ffa500;"># 好像要用unicode字符 不然找不到 囧啊</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">/logo/xxx1.jpg</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;">={</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">type</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">logo</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">size</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: Maroon;">1</span><span style="color: Gray;">}<br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">/logo/xxx2.jpg</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;">={</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">type</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">logo</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">size</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: Maroon;">2</span><span style="color: Gray;">}<br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">/logo/xxx3.jpg</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;">={</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">type</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">logo</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">size</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: Maroon;">3</span><span style="color: Gray;">}<br /></span><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">/logo/xxx4.jpg</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;">={</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">type</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">logo</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">size</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:</span><span style="color: Maroon;">4</span><span style="color: Gray;">}</span></div></div>
<p><strong>Map函数</strong></p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">map_fun</span><span style="color: Gray;"> = </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'''</span><span style="color: Red;"><br />function(doc) {<br />&nbsp;&nbsp; if (doc.type=='logo')<br />&nbsp;&nbsp; &nbsp; &nbsp; emit(doc._id, doc.size);<br />}<br /></span><span style="color: #8b0000;">'''</span><span style="color: Gray;"><br />&nbsp;<br /></span><span style="color: Green;">for</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">query</span><span style="color: Olive;">(</span><span style="color: Blue;">map_fun</span><span style="color: Olive;">)</span><span style="color: Gray;">:<br />&nbsp;&nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span></div></div>
<p>输出</p>
<div class="hl-surround"><div class="hl-main">&lt;Row id=u'logo/xxx1.jpg', key=u'logo/xxx1.jpg', value=1&gt;<br />&lt;Row id=u'logo/xxx2.jpg', key=u'logo/xxx2.jpg', value=2&gt;<br />&lt;Row id=u'logo/xxx3.jpg', key=u'logo/xxx3.jpg', value=3&gt;<br />&lt;Row id=u'logo/xxx4.jpg', key=u'logo/xxx4.jpg', value=4&gt;</div></div>
<p>我们还可以加上reduce函数，比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">reduce_fun</span><span style="color: Gray;"> = </span><span style="color: Blue;">u</span><span style="color: #8b0000;">'''</span></li>
<li><span style="color: Red;">function(keys, values, rereduce) {</span></li>
<li><span style="color: Red;">&nbsp;&nbsp; return sum(values)</span></li>
<li><span style="color: Red;">}</span></li>
<li><span style="color: #8b0000;">'''</span></li>
<li><span style="color: Green;">for</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">row</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">query</span><span style="color: Olive;">(</span><span style="color: Blue;">map_fun</span><span style="color: Gray;">,</span><span style="color: Blue;">reduce_fun</span><span style="color: Olive;">)</span><span style="color: Gray;">:</span></li>
<li><span style="color: Gray;">&nbsp;&nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">row</span></li></ol></div>
<p>输出</p>
<div class="hl-surround"><div class="hl-main">&lt;Row key=None, value=10&gt;</div></div>
<p>reduce 中 rereduce变量的含义如下</p>
<ol>
<li>rereduce为false</li>
<ul>
<li>key为array，element为：[key,id]，key为map function产生的key，id为Document对应id</li>
<li>values为array，elements为map function产生的结果</li>
<li>比如 reduce([ [key1,id1], [key2,id2], [key3,id3] ],[value1,value2,value3], false)</li>
</ul>
<li>rereduce为true</li>
<ul>
<li>key为null</li>
<li>values为array，element为前一次reduce返回的结果</li>
<li>比如reduce(null, [中间结果1,中间结果2,中间结果3], true)</li>
</ul>
</ol>
<p>[<a href="http://labs.mudynamics.com/wp-content/uploads/2009/04/icouch.html" target=_blank>这里</a>]有一些map/reduce演示的例子,比较好懂.</p>
<p><strong>Creating Views</strong><br />
View 可以理解为索引了 不过这个索引不是实时的&#8230;<br />
接着上文的例子</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Blue;">db</span><span style="color: Olive;">[</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">_design/test</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">]</span><span style="color: Gray;">=</span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">views</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">:<br />&nbsp;</span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;&nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">all</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">map</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">function(doc) { if (doc.type == 'logo')&nbsp; emit(null, doc) }</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"><br />&nbsp;&nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,<br />&nbsp;&nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">size_large_than_2</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">map</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">function(doc) { if (doc.size &amp;&amp; parseInt(doc.size)&gt;2)<br />emit(null,doc) }</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"><br />&nbsp;&nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,<br />&nbsp;&nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">total_size</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: Olive;">{</span><span style="color: Gray;"><br />&nbsp;&nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">map</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">function(doc) { emit(null,parseInt(doc.size)) }</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,<br />&nbsp;&nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">reduce</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">function(keys,values) { return sum(values) }</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"><br />&nbsp;&nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;"><br />&nbsp;</span><span style="color: Olive;">}</span><span style="color: Gray;"><br /></span><span style="color: Olive;">}</span></div></div>
<p>然后刷新</p>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/_utils/database.html?python-tests</div></div>
<p>可以看到 select views中多了test，也可访问：</p>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/python-tests/_design/test/_view/all</div></div>
<p>可以加上limit这一类参数</p>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/python-tests/_design/test/_view/all?limit=2</div></div>
<div class="hl-surround"><div class="hl-main">http://123.123.123.123:12345/python-tests/_design/test/_view/all?limit=2&amp;skip=1</div></div>
<p>这样可以分页,不过[<a href="http://stackoverflow.com/questions/312163/pagination-in-couchdb" target=_blank>这里</a>]提到</p>
<blockquote><p>A simpler method of doing this is to use the skip parameter to work out the starting document for the page, however this method should be used with caution. The skip \parameter simply causes the internal engine to not return entries that it is iterating over. While this gives the desired behaviour it is much slower than finding the first document for the page by key. The more documents that are skipped, the slower the request will be.</p></blockquote>
<p>所以最好配合下面的startkey之类的来用skip<br />
类似参数还有:</p>
<ul>
<li>排序 descending=false</li>
<li>开始结束 startkey=&#8221;abc&#8221;&#038;endkey=&#8221;abcZZZZZZZZZ&#8221; 可以用 docid startkey_docid=null</li>
<li>合并结果 group=true 用法有点复杂,可以看[<a href="http://jchrisa.net/drl/_design/sofa/_show/post/markov_chains_using_couchdb_s_g" target=_blank>这里</a>]</li>
</ul>
<p>key可以是复杂的key,比如:</p>
<blockquote><p> The query startkey=["foo"]&#038;endkey=["foo",{}] will match most array keys with &#8220;foo&#8221; in the first element, such as ["foo","bar"] and ["foo",["bar","baz"]]. However it will not match ["foo",{"an":"object"}] </p></blockquote>
<p>python中可以这样访问</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Green;">for</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">view</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">_design/test/_view/all</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">:<br />&nbsp;&nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;">.</span><span style="color: Blue;">id</span></div></div>
<p>输出</p>
<div class="hl-surround"><div class="hl-main">logo/xxx1.jpg<br />logo/xxx2.jpg<br />logo/xxx3.jpg<br />logo/xxx4.jpg</div></div>
<p>又如</p>
<div class="hl-surround"><div class="hl-main"><span style="color: Green;">for</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">view</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">_design/test/_view/size_large_than_2</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">:<br />&nbsp;&nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;"> </span><span style="color: Blue;">row</span></div></div>
<p>输出</p>
<div class="hl-surround"><div class="hl-main">&lt;Row id=u'logo/xxx3.jpg', key=None, value={u'_rev': u'1-3347158087',<br />u'_id': u'logo/xxx3.jpg', u'type': u'logo', u'size': 3}&gt;<br />&lt;Row id=u'logo/xxx4.jpg', key=None, value={u'_rev': u'1-1107796651',<br />u'_id': u'logo/xxx4.jpg', u'type': u'logo', u'size': 4}&gt;</div></div>
<p><strong>网络资源</strong></p>
<ul>
<li>[<a href="http://hi.baidu.com/freeway2000/blog/item/8f76ed11f26bc8c1a6ef3f53.html" target=_blank>这里</a>]有一篇中文的简介,可以看看作为背景知识.</li>
<li>[<a href="http://books.couchdb.org/relax/" target=_blank>CouchDB: The Definitive Guide</a>]</li>
</ul>
<p><strong>注</strong></p>
<ol>
<li>根据网上的测试表明:couchdb 写入速度 比 mysql 慢4倍,创建索引速度 比 mysql 慢50倍</li>
<li>couchdb 只写入不删除,需要定期做整理,类似垃圾回收的copy+删除,需要预留大量磁盘空间.</li>
<li>索引不是实时的,你可能看到的是旧的数据</li>
</ol>
<p><strong>我的个人看法</strong><br />
单单看性能,couchdb的确很不理想,但是couchdb可以把数据以view的方式展现,要什么,就新建什么样的view,这种随心所欲索引方式,在不少应用的场合,通过view的方式把这种查询结果持久化,可以大大减少了把传统意义上的重复且相似查询.</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/couchdb-guide.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Tail Recursion in C [一]</title>
		<link>http://erlang-china.org/misc/tail-recursion-in-c-%e4%b8%80.html</link>
		<comments>http://erlang-china.org/misc/tail-recursion-in-c-%e4%b8%80.html#comments</comments>
		<pubDate>Fri, 27 Mar 2009 08:12:38 +0000</pubDate>
		<dc:creator>ph4nut</dc:creator>
				<category><![CDATA[misc]]></category>
		<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=459</guid>
		<description><![CDATA[看了《写出正确的尾递归代码》一文，对尾递归的作用有了表面上的理解，但是关于编译器如何优化尾递归为一条跳转指令以及对递归堆栈的处理还不是很清楚。所以有了这篇小文，有什么错误的地方还请各位看官指出。 先来看一下在C语言里一个尾递归的例子： #include &#38;lt;stdio.h&#38;gt;   void&#160;add( int  n) {     printf(&#160;&#34; %d\n&#34;,n);     add(n + 1); }   int&#160;main() {     add(0);     return&#160;0; } 编译这段代码：gcc -o  add.exe add.c 如果运行这个程序的话，当n增加到一定值的话，程序就会推出，因为栈空间不够。 再来用gcc的O2选项(这个选项增加了对尾递归的优化)来优化这段代码并运行：gcc -o add.exe add.c  -O2 如果你运行这个程序，你会发现一直打印递增的n,而没有停止。 接下来我们来比较一下没有优化尾递归和优化后的汇编代码。 未优化尾递归的汇编代码：gcc -S add.c  .file &#34;add.c&#34;  .section .rdata,&#34;dr&#34; LC0:  .ascii &#34; %d\12&#34;  .text .globl _add  .def _add; .scl 2; .type 32; .endef _add:  pushl %ebp  movl %esp, %ebp  subl $8, [...]]]></description>
			<content:encoded><![CDATA[<p>看了<a href="http://erlang-china.org/study/the-right-tail-recursive.html" target="_blank">《写出正确的尾递归代码》</a>一文，对尾递归的作用有了表面上的理解，但是关于编译器如何优化尾递归为一条跳转指令以及对递归堆栈的处理还不是很清楚。所以有了这篇小文，有什么错误的地方还请各位看官指出。</p>
<p>先来看一下在C语言里一个尾递归的例子：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-prepro">#include &amp;lt;stdio.h&amp;gt;</span></li>
<li><span style="color: Gray;"> </span></li>
<li><span class="hl-types">void</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">add</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span class="hl-types">int</span><span style="color: Gray;">  </span><span style="color: Blue;">n</span><span style="color: Olive;">)</span></li>
<li><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">    </span><span style="color: Blue;">printf</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;"> %d</span><span style="color: Navy;">\</span><span style="color: Red;">n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">    </span><span style="color: Blue;">add</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;"> </span></li>
<li><span class="hl-types">int</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">main</span><span style="color: Olive;">()</span></li>
<li><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">    </span><span style="color: Blue;">add</span><span style="color: Olive;">(</span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">    </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Maroon;">0</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>编译这段代码：gcc -o  add.exe add.c</p>
<p>如果运行这个程序的话，当n增加到一定值的话，程序就会推出，因为栈空间不够。</p>
<p>再来用gcc的O2选项(这个选项增加了对尾递归的优化)来优化这段代码并运行：gcc -o add.exe add.c  -O2</p>
<p>如果你运行这个程序，你会发现一直打印递增的n,而没有停止。</p>
<p>接下来我们来比较一下没有优化尾递归和优化后的汇编代码。</p>
<p>未优化尾递归的汇编代码：gcc -S add.c</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"> .file &quot;add.c&quot;</li>
<li> .section .rdata,&quot;dr&quot;</li>
<li>LC0:</li>
<li> .ascii &quot; %d\12&quot;</li>
<li> .text</li>
<li>.globl _add</li>
<li> .def _add; .scl 2; .type 32; .endef</li>
<li>_add:</li>
<li> pushl %ebp</li>
<li> movl %esp, %ebp</li>
<li> subl $8, %esp</li>
<li> movl 8(%ebp), %eax</li>
<li> movl %eax, 4(%esp)</li>
<li> movl $LC0, (%esp)</li>
<li> call _printf</li>
<li> movl 8(%ebp), %eax</li>
<li> incl %eax</li>
<li> movl %eax, (%esp)</li>
<li> call _add  ;注意这里，add函数的调用</li>
<li> leave</li>
<li> ret</li>
<li> .def ___main; .scl 2; .type 32; .endef</li>
<li>.globl _main</li>
<li> .def _main; .scl 2; .type 32; .endef</li>
<li>_main:</li>
<li> pushl %ebp</li>
<li> movl %esp, %ebp</li>
<li> subl $8, %esp</li>
<li> andl $-16, %esp</li>
<li> movl $0, %eax</li>
<li> addl $15, %eax</li>
<li> addl $15, %eax</li>
<li> shrl $4, %eax</li>
<li> sall $4, %eax</li>
<li> movl %eax, -4(%ebp)</li>
<li> movl -4(%ebp), %eax</li>
<li> call __alloca</li>
<li> call ___main</li>
<li> movl $0, (%esp)</li>
<li> call _add</li>
<li> movl $0, %eax</li>
<li> leave</li>
<li> ret</li>
<li> .def _printf; .scl 3; .type 32; .endef</li></ol></div>
<p>优化了尾递归的汇编代码：gcc -O2 add.c</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"> .file &quot;add.c&quot;</li>
<li> .section .rdata,&quot;dr&quot;</li>
<li>LC0:</li>
<li> .ascii &quot; %d\12 &quot;</li>
<li> .text</li>
<li> .p2align 4,,15</li>
<li>.globl _add</li>
<li> .def _add; .scl 2; .type 32; .endef</li>
<li>_add:</li>
<li> pushl %ebp</li>
<li> movl %esp, %ebp</li>
<li> pushl %ebx</li>
<li> subl $20, %esp</li>
<li> movl 8(%ebp), %ebx</li>
<li> .p2align 4,,15</li>
<li>L2:</li>
<li> movl %ebx, 4(%esp)</li>
<li> incl %ebx</li>
<li> movl $LC0, (%esp)</li>
<li> call _printf</li>
<li> jmp L2  ;注意这里，尾递归被优化成了一条跳转指令。</li>
<li> .def ___main; .scl 2; .type 32; .endef</li>
<li> .p2align 4,,15</li>
<li>.globl _main</li>
<li> .def _main; .scl 2; .type 32; .endef</li>
<li>_main:</li>
<li> pushl %ebp</li>
<li> movl $16, %eax</li>
<li> movl %esp, %ebp</li>
<li> subl $8, %esp</li>
<li> andl $-16, %esp</li>
<li> call __alloca</li>
<li> call ___main</li>
<li> movl $0, (%esp)</li>
<li> call _add</li>
<li>&nbsp;</li>
<li>leave</li>
<li> xorl %eax, %eax</li>
<li> ret</li>
<li> .def _printf; .scl 3; .type 32; .endef</li></ol></div>
<p>从上面两段代码看来，add函数的确有差别，但是重点在于，优化后对堆栈的处理。还是在来看优化后的代码片段（跟上面的一样，只不过我摘取了重点）</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">_add:</li>
<li> pushl %ebp  ;标记1</li>
<li> movl %esp, %ebp</li>
<li> pushl %ebx</li>
<li> subl $20, %esp</li>
<li> movl 8(%ebp), %ebx</li>
<li> .p2align 4,,15  ;标记2</li>
<li>&nbsp;</li>
<li>L2:</li>
<li> movl %ebx, 4(%esp)</li>
<li> incl %ebx</li>
<li> movl $LC0, (%esp)</li>
<li> call _printf</li>
<li> jmp L2</li>
<li> .def ___main; .scl 2; .type 32; .endef</li>
<li> .p2align 4,,15</li></ol></div>
<p>从标记1 &#8211; 标记2，这段代码在add函数递归的过程只执行了一遍，这就说明了，优化后的代码，在堆栈上分配参数的时候，只分配了一次，也就是在第一次调用add函数的时候，现在我们终于明白了尾递归为什么不消耗栈的原因了。同样的，如果在add函数里定义了一些变量（当然要在递归调用的前面），变量在堆栈上也只是分配了一次。</p>
<p>到此，尾递归这个问题也应该告一段落了，但是还有一个问题值得一提，上面的add函数是个无限的递归，永不返回，如果再加一个递归终结的条件，当add函数（也就是最深一层的add函数）返回的时候，它不是向上一层递归地返回，而是直接跳到第一个add调用者（在这个例子应该是main函数）的下一个语句。这个下一篇文章在详细解释吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/misc/tail-recursion-in-c-%e4%b8%80.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>问个非常初级的问题</title>
		<link>http://erlang-china.org/study/about_epl_license.html</link>
		<comments>http://erlang-china.org/study/about_epl_license.html#comments</comments>
		<pubDate>Thu, 15 Jan 2009 10:38:21 +0000</pubDate>
		<dc:creator>huzht</dc:creator>
				<category><![CDATA[study]]></category>
		<category><![CDATA[erlang 授权]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=379</guid>
		<description><![CDATA[我用了1天把erlang的EPL协议（也就是MPL协议改的），读了一下，感觉还有点没明白，我想问问如果我只使用默认配套的.beam文件和他的运行时环境，当然我肯定要自己做一些逻辑上的模块函数什么的，不包含他的.beam，只使用他的.beam，也不更改他的任何.erl文件，这样应该可以免费闭源使用吧？希望高手指点指点，谢谢！]]></description>
			<content:encoded><![CDATA[<p>我用了1天把erlang的EPL协议（也就是MPL协议改的），读了一下，感觉还有点没明白，我想问问如果我只使用默认配套的.beam文件和他的运行时环境，当然我肯定要自己做一些逻辑上的模块函数什么的，不包含他的.beam，只使用他的.beam，也不更改他的任何.erl文件，这样应该可以免费闭源使用吧？希望高手指点指点，谢谢！</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/about_epl_license.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>erlang 的源代码保护机制</title>
		<link>http://erlang-china.org/study/erlang_sourcecode_protect.html</link>
		<comments>http://erlang-china.org/study/erlang_sourcecode_protect.html#comments</comments>
		<pubDate>Wed, 14 Jan 2009 06:25:40 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[study]]></category>
		<category><![CDATA[protect]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[sourcecode]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=354</guid>
		<description><![CDATA[稍微深入研究过一点 java 的同学，恐怕都知道什么叫做 “反编译” 。也就是说，随便拿一个 class 文件，找一个 jad 来，所有的 “智慧结晶” 就全都 “真相大白” 了，跟原先的 source code 相比，区别只是没有注释而已。 对于开源软件开发者来说，这本是无所谓的事，但对于商业开发者而言，这简直就是噩梦。在 java 的世界，道高一尺魔高一丈(及其反复迭代)的结果是，这件事最终演变得比较诡异，以至于专门诞生了一个名叫 “代码混淆” 的产业。在我上一次关注的时候，这个领域的最新进展是可以 “混淆” 程序执行的流程，以至于正常的人类阅读反编译出来的源码，将会导致严重的脑残。不过，传说又出了个叫做 “流程优化器” 的东东……(这个故事未完待续)。 其实，这件事困扰的不仅只是 java ，几乎所有 “有源代码” 的程序都有这个烦恼。比如，饱受折磨的还有 php, asp 以及 .net。不知道有没有高人能从 “机器码” 反编译出 C 和 C++ 的源程序呢，反正我挺好奇的。不过，话说回来， “没有源代码” 的程序，恐怕还真的没有。保护源代码，在我们现如今 “处处是山寨，遍地是豺狼” 的产业现状之下，似乎仍然是个不得不认真对待的事情。 在源代码保护的问题上，Erlang 的表现又会如何？今天体验了一把，应该说，设计得很细致，至于说这样的设计是否能够完全杜绝源代码的泄露，这个问题恐怕仍然需要留给 “专家” 们去研究。好吧，口水就喷到这里，下面上干货。 目前这个阶段，对 Erlang 源代码的保护，主要是在 debug_info 上做手脚，因为，在 debug_info 里面有完整的源代码，可以极其轻松的从中 [...]]]></description>
			<content:encoded><![CDATA[<p>稍微深入研究过一点 java 的同学，恐怕都知道什么叫做 “反编译” 。也就是说，随便拿一个 class 文件，找一个 jad 来，所有的 “智慧结晶” 就全都 “真相大白” 了，跟原先的 source code 相比，区别只是没有注释而已。</p>
<p>对于开源软件开发者来说，这本是无所谓的事，但对于商业开发者而言，这简直就是噩梦。在 java 的世界，道高一尺魔高一丈(及其反复迭代)的结果是，这件事最终演变得比较诡异，以至于专门诞生了一个名叫 “代码混淆” 的产业。在我上一次关注的时候，这个领域的最新进展是可以 “混淆” 程序执行的流程，以至于正常的人类阅读反编译出来的源码，将会导致严重的脑残。不过，传说又出了个叫做 “流程优化器” 的东东……(这个故事未完待续)。</p>
<p>其实，这件事困扰的不仅只是 java ，几乎所有 “有源代码” 的程序都有这个烦恼。比如，饱受折磨的还有 php, asp 以及 .net。不知道有没有高人能从 “机器码” 反编译出 C 和 C++ 的源程序呢，反正我挺好奇的。不过，话说回来， “没有源代码” 的程序，恐怕还真的没有。保护源代码，在我们现如今 “处处是山寨，遍地是豺狼” 的产业现状之下，似乎仍然是个不得不认真对待的事情。</p>
<p>在源代码保护的问题上，Erlang 的表现又会如何？今天体验了一把，应该说，设计得很细致，至于说这样的设计是否能够完全杜绝源代码的泄露，这个问题恐怕仍然需要留给 “专家” 们去研究。好吧，口水就喷到这里，下面上干货。<br />
<span id="more-354"></span><br />
目前这个阶段，对 Erlang 源代码的保护，主要是在 debug_info 上做手脚，因为，在 debug_info 里面有完整的源代码，可以极其轻松的从中 “找回” 源码(两个语句而已，在官方文档之中都有例子)。</p>
<p>先看如何从 Erlang 的 beam 文件获取源代码。象这样的一个简单程序：</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;">a</span><span style="color: Olive;">)</span><span style="color: Gray;">.<br />&nbsp;<br />-</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">test</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Olive;">])</span><span style="color: Gray;">.<br />&nbsp;<br /></span><span style="color: Blue;">test</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;<br />&nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">source code.~n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></div></div>
<p>带 debug_info 编译，并运行之。</p>
<div class="hl-surround"><div class="hl-main">$ erlc +debug_info a.erl<br />$ erl -s a test -s c q -noshell<br />source code.<br />$</div></div>
<p>我们可以这样还原它的源码：</p>
<div class="hl-surround"><div class="hl-main">$ erl<br />1&gt;&nbsp; {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(code:which(a), abstract_code]).<br />{ok,{a,[{abstract_code,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{raw_abstract_v1,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[{attribute,1,file,{&quot;./a.erl&quot;,1}},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {attribute,1,module,a},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {attribute,3,export,[{test,0}]},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {function,5,test,0,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [{clause,5,[],[],[{call,6,{remote,...},[...]}]}]},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {eof,7}]}}]}}<br />2&gt; io:fwrite(&quot;~s~n&quot;, [erl_prettypr:format(erl_syntax:form_list(AC))]).<br />-file(&quot;./a.erl&quot;, 1).<br /><br />-module(a).<br /><br />-export([test/0]).<br /><br />test() -&gt; io:format(&quot;source code.~n&quot;, []).<br /><br /><br />ok<br />3&gt;</div></div>
<p>看，和源码几乎完全一致。</p>
<p>那么，如果我们编译的时候不带 debug_info 呢？是的，完全可以。不过，如果你想要在这样的 beam 上执行 debugger 或者 xref 之类的动作，那么，没有 debug_info 就做不了。天知道我们会不会有需要做 “现场调试” 的时候呢。有没有既保留 debug_info 又阻止其他人通过 debug_info 来得到源码的办法呢？有，那就是——加密 debug_info 。</p>
<p>首先建立一个 ~/.erlang.crypt 文件，内容如下：</p>
<div class="hl-surround"><div class="hl-main">$ cat ~/.erlang.crypt<br />[{debug_info, des3_cbc, [], &quot;my_source_code_secret_key&quot;}].</div></div>
<p>这里的 &#8220;my_source_code_secret_key&#8221; 就被用来生成对 debug_info 加密的密钥。用 encrypt_debug_info 参数编译，并运行之。</p>
<div class="hl-surround"><div class="hl-main">$ erlc +encrypt_debug_info a.erl<br />$ erl -s a test -s c q -noshell<br />source code.</div></div>
<p>现在拿掉 ~/.erlang.crypt (模拟生产机环境)，看看能否正常运行。</p>
<div class="hl-surround"><div class="hl-main">$ mv ~/.erlang.crypt ~/.erlang.old.crypt<br />$ erl -s a test -s c q -noshell<br />source code.</div></div>
<p>运行没问题。此时，是否还能还原源码呢。</p>
<div class="hl-surround"><div class="hl-main">$ erl<br />1&gt;&nbsp; beam_lib:chunks(code:which(a), [abstract_code]).<br />{error,beam_lib,<br />&nbsp;&nbsp; &nbsp; &nbsp; {key_missing_or_invalid,&quot;./a.beam&quot;,abstract_code}}</div></div>
<p>这正是我们想要的。</p>
<p>比如说，假如某日我们需要在这台生产机上做 “现场调试”，那就再加上 ~/.erlang.crypt 文件。作为验证，我们再执行一次还原源码的操作。</p>
<div class="hl-surround"><div class="hl-main">$ mv ~/.erlang.old.crypt ~/.erlang.crypt<br />$ erl<br />1&gt;&nbsp; {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(code:which(a), abstract_code]).<br />{ok,{a,[{abstract_code,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{raw_abstract_v1,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[{attribute,1,file,{&quot;./a.erl&quot;,1}},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {attribute,1,module,a},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {attribute,3,export,[{test,0}]},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {function,5,test,0,<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [{clause,5,[],[],[{call,6,{remote,...},[...]}]}]},<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {eof,7}]}}]}}<br />2&gt; io:fwrite(&quot;~s~n&quot;, [erl_prettypr:format(erl_syntax:form_list(AC))]).<br />-file(&quot;./a.erl&quot;, 1).<br /><br />-module(a).<br /><br />-export([test/0]).<br /><br />test() -&gt; io:format(&quot;source code.~n&quot;, []).<br /><br /><br />ok<br />3&gt;</div></div>
<p>看 debug_info 还原出来了。</p>
<p>我们藏在 debug_info 中的源码是被 des3_cbc 算法保护起来的，有兴趣的童鞋可以去 wiki 百科了解它的加密强度，解开它的关键是 ~/.erlang.crypt 文件，只要它不泄露，那么在生产环境下，我们的代码就仍然是安全的，也就是说，就算这台机器被黑掉了，也还原不出源码(如果我说错了，请纠正我)，而且只要你持有 .erlang.crypt 文件，(在需要的时候)仍然可以进行调试。</p>
<p>实验之前，确实没想到 Erlang 还设计了这么一个机制，挺细致的。需要说明的是，上述方案是对 beam 中的 debug_info 进行了加密，从而阻止其他人从中获取源码，至于是否还有其他的还原源码的可能，目前还不是很清楚。比如，理论上，是否有可能通过 beam 之中的 op code 反编译出原始的 source code 呢？对于这个话题，如果有童鞋知道，请不吝赐教。</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/erlang_sourcecode_protect.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Mnesia的分布式</title>
		<link>http://erlang-china.org/study/mnesia_dist.html</link>
		<comments>http://erlang-china.org/study/mnesia_dist.html#comments</comments>
		<pubDate>Thu, 18 Dec 2008 15:05:04 +0000</pubDate>
		<dc:creator>Godwit</dc:creator>
				<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://erlang-china.org/misc/mnesia%e7%9a%84%e5%88%86%e5%b8%83%e5%bc%8f.html</guid>
		<description><![CDATA[Mnesia的分布式如何使用呢？做了个简单的测试： 代码如下： -module( db ). -compile(&#160;export_all ). -include_lib(&#160;&#34;stdlib/include/qlc.hrl&#34; ). -include_lib(&#160;&#34;eunit/include/eunit.hrl&#34; ). &#160; %% player -record(&#160;player, { oid,&#160; &#160; &#160; &#160; %% object id username } ). &#160; table_data() -&#62; [&#160;%% The player table { player, 1, &#34;david1&#34; }, { player, 2, &#34;david2&#34; }, { player, 3, &#34;david3&#34; }, { player, 4, &#34;david4&#34; }, { player, [...]]]></description>
			<content:encoded><![CDATA[<p>Mnesia的分布式如何使用呢？做了个简单的测试：<br />
代码如下：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">-</span><span style="color: Blue;">compile</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">export_all</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">-</span><span style="color: Blue;">include_lib</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">stdlib/include/qlc.hrl</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">-</span><span style="color: Blue;">include_lib</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">eunit/include/eunit.hrl</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: #ffa500;">%% player</span></li>
<li><span style="color: Gray;">-</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">player</span><span style="color: Gray;">, {</span></li>
<li><span style="color: Blue;">oid</span><span style="color: Gray;">,&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% object id</span></li>
<li><span style="color: Blue;">username</span></li>
<li><span style="color: Gray;">} </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">table_data</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">%% The player table</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">david1</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">david2</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Maroon;">3</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">david3</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Maroon;">4</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">david4</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Maroon;">5</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">david5</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> }</span></li>
<li><span style="color: Olive;">]</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">set_table_data</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">clear_table</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">player</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">F</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">foreach</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">fun</span><span style="color: Gray;"> </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">write</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">table_data</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">transaction</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">F</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">install</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Nodes</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_list</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">Nodes</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">delete_schema</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Nodes</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Green;">catch</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">create_schema</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">Nodes</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">create_table</span><span style="color: Gray;"> </span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">player</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">disc_copies</span><span style="color: Gray;">, </span><span style="color: Blue;">Nodes</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">type</span><span style="color: Gray;">, </span><span style="color: Blue;">set</span><span style="color: Gray;"> },</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">attributes</span><span style="color: Gray;">, </span><span style="color: Blue;">record_info</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fields</span><span style="color: Gray;">, </span><span style="color: Blue;">player</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> }</span></li>
<li><span style="color: Olive;">]</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">atomic</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;"> } -&gt;</span></li>
<li><span style="color: Blue;">ok</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">_Any</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">create table error!~n</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span></li>
<li><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">do</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Q</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">F</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">qlc</span><span style="color: Gray;">:</span><span style="color: Blue;">e</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Q</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">{ </span><span style="color: Blue;">atomic</span><span style="color: Gray;">, </span><span style="color: Blue;">Val</span><span style="color: Gray;"> } = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">transaction</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">F</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">Val</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">demo</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">select_player</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Blue;">do</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">qlc</span><span style="color: Gray;">:</span><span style="color: Blue;">q</span><span style="color: Olive;">([</span><span style="color: Gray;"> </span><span style="color: Blue;">X</span><span style="color: Gray;"> || </span><span style="color: Blue;">X</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">set_table_data</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span></li></ol></div>
<p>俺用的是windows系统，在控制台下：</p>
<div class="hl-surround"><div class="hl-main">erl -sname a<br />Eshell V5.6.3&nbsp; (abort with ^G)<br />(a@godwit)1&gt; db:install( [node()] ).<br />ok<br />(a@godwit)2&gt; db:init().<br />stopped<br /><br />=INFO REPORT==== 18-Dec-2008::22:42:54 ===<br />application: mnesia<br />exited: stopped<br />type: temporary<br /><br />(a@godwit)4&gt; mnesia:start().<br />ok<br />(a@godwit)5&gt; tv:start().   %% 这里你可以看到数据库内容。</div></div>
<p>然后在另一个控制台下：</p>
<div class="hl-surround"><div class="hl-main">erl -sname b -mnesia extra_db_nodes [a@godwit]<br />Eshell V5.6.3&nbsp; (abort with ^G)<br />(b@godwit)1&gt; mnesia:start().<br />ok<br />(b@godwit)2&gt; tv:start(). %% 查看数据库内容，已经拷贝过来了！！！</div></div>
<p>Bingo！一般人我不告诉他！<br />
PS：博主，我不知道我贴这么幼稚的文章行不行？:)</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/study/mnesia_dist.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

