<?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>Here comes the Sun &#187; 手艺</title>
	<atom:link href="http://sunng.info/blog/category/%e6%89%8b%e8%89%ba/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>47% users on this site use *nix</description>
	<lastBuildDate>Sat, 04 Feb 2012 13:08:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>使用Enlive作为模板引擎</title>
		<link>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/</link>
		<comments>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 13:13:19 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1125</guid>
		<description><![CDATA[在所有的clojure web开发例子里，对模板的介绍都很少。很多的简单例子都是以hiccup作为页面生成的手段。hiccup是个clojure的html DSL，例子里用这样的DSL生成页面确实很酷，可是他是real world吗，当然不是。 好在clojure世界里早就有了enlive，它不仅是一个通过css selector解析html的库，本身也可以作为模板引擎应用在web开发中。我不知道这种通过css selector的方式是否是enlive首创，不过他实在是非常新颖独特，而且平滑了页面设计和程序的集成。 例如这样一个模板 index.html： &#60;div id=&#34;cc&#34;&#62;Sample Text&#60;/div&#62; 在clojure程序中，使用enlive的deftemplate &#40;deftemplate index &#34;index.html&#34; &#160; &#91;ctx&#93; &#160; &#91;:div#cc&#93; &#40;content &#40;:data ctx&#41;&#41;&#41; 在控制器里，可以很MVC地渲染页面 &#40;index &#123;:data &#34;rendered text&#34;&#125;&#41; 除了content用于渲染文本，还有html-content可以渲染含html标签的内容，以及set-attr用来修改页面元素的属性。 和传统的模板引擎相比，最大的不同是enlive里没有嵌入模板的直观的控制流，没有循环和条件判断，但是并非不可实现。 循环输出一组list 页面 list.html &#60;ul id=&#34;the-list&#34;&#62; &#60;li class=&#34;list-item&#34;&#62;&#60;/li&#62; &#60;/ul&#62; 定义一个enlive的snippet &#40;defsnippet &#8230; <a href="http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在所有的clojure web开发例子里，对模板的介绍都很少。很多的简单例子都是以hiccup作为页面生成的手段。hiccup是个clojure的html DSL，例子里用这样的DSL生成页面确实很酷，可是他是real world吗，当然不是。</p>
<p>好在clojure世界里早就有了enlive，它不仅是一个通过css selector解析html的库，本身也可以作为模板引擎应用在web开发中。我不知道这种通过css selector的方式是否是enlive首创，不过他实在是非常新颖独特，而且平滑了页面设计和程序的集成。</p>
<p>例如这样一个模板 index.html：</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cc&quot;</span>&gt;</span>Sample Text<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></div></div>
<p>在clojure程序中，使用enlive的deftemplate</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate index <span style="color: #ff0000;">&quot;index.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">div</span>#cc<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">data</span> ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>在控制器里，可以很MVC地渲染页面</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>index <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">data</span> <span style="color: #ff0000;">&quot;rendered text&quot;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>除了content用于渲染文本，还有html-content可以渲染含html标签的内容，以及set-attr用来修改页面元素的属性。</p>
<p>和传统的模板引擎相比，最大的不同是enlive里没有嵌入模板的直观的控制流，没有循环和条件判断，但是并非不可实现。</p>
<p>循环输出一组list</p>
<p>页面 list.html</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;the-list&quot;</span>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;list-item&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span></div></div>
<p>定义一个enlive的snippet</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defsnippet item<span style="color: #66cc66;">-</span>model <span style="color: #ff0000;">&quot;page.html&quot;</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #66cc66;">.</span>list<span style="color: #66cc66;">-</span>item<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #66cc66;">.</span>list<span style="color: #66cc66;">-</span>item<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">data</span> ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>在页面模板里</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate list<span style="color: #66cc66;">-</span>page <span style="color: #ff0000;">&quot;list.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">ul</span>#the<span style="color: #66cc66;">-</span>list<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">map</span> item<span style="color: #66cc66;">-</span>model <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">some</span><span style="color: #66cc66;">-</span>list ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>这样在页面里列表项会被循环输出，而在页面设计时这里可以放任意个li，并且直接交给后台作为模板。</p>
<p>条件判断</p>
<p>页面，设计时显示所有的内容 msg.html</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/span.html"><span style="color: #000000; font-weight: bold;">span</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;msg&quot;</span>&gt;</span>只在一定条件下显示<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/span.html"><span style="color: #000000; font-weight: bold;">span</span></a>&gt;</span></div></div>
<p>在模板中通过clojure的if进行判断</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate msg <span style="color: #ff0000;">&quot;msg.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">span</span>#msg<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">show</span> ctx<span style="color: #66cc66;">&#41;</span> identity <span style="color: #66cc66;">&#40;</span>html<span style="color: #66cc66;">-</span>content <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>解决了这两个问题，基本上用enlive作为模板引擎就没有障碍了。不过enlive也有一点小问题，其一可能是性能的问题，方便的selector显然要比传统的模板语言消耗更多的CPU。另外，在开发过程里，页面文件在服务器启动后不能热加载，修改页面必须重启ring才能看到。也许有时间的话，可以给它加一个reload选项。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用Clojure Thread Macro的心得</title>
		<link>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/</link>
		<comments>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 14:44:00 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[macro]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1096</guid>
		<description><![CDATA[Thread Macro是clojure里一个很强大的宏，他帮助你简化嵌套函数的调用，比如 &#40;str &#40;inc &#40;count &#91;:a :b&#93;&#41;&#41;&#41; 就可以利用thread macro简写成 &#40;-&#62; &#91;:a :b&#93; count inc str&#41; -&#62;&#62;和-&#62;类似，区别在于-&#62;&#62;把值作为函数的最后一个参数传入。 简单的功能介绍完了，接下来就遇到问题了。我需要功能，能够接受一个或多个函数，然后把这些函数组成一个pipeline。这时很自然想到-&#62;是一个好帮手。也许只需要一个类似这样的form就可以了： #(apply -&#62; % [funcs])。结果失败了，因为-&#62;是个宏，所以根本不能用apply。于是想到有apply-macro吗？有，或者说曾经有过。在contrib中曾经有一个apply-macro，不过被强烈不推荐使用。到这里，这条路堵死了，惟一的办法就是把-&#62;放到API之外，放到用户代码里去。 放到用户代码里，你需要写一个详细的说明文档并且告诉用户他必须这么做。然而在clojure世界里有一个更好的办法就是再写一个宏把-&#62;包装起来。这么做看似多此一举，其实是保持了API的一致性。通过宏，我们可以把自己的API延伸到用户代码中去。或者说，通过一个类似DSL的宏，给一些并不优雅的API一个缓冲，也为API日后的演化留下空间。 这里还要扯开一句关于宏的开发。clojure中所谓code is data，主要就是体现在宏里。原本在多数其他语言里，宏是不能求值的。但是在clojure里，由于code is data的缘故，宏是可以求值的。所有的输入数据都是list，你可以做first/reverse这样的操作。但是有一点要注意的是，宏中求得的值和代码里的值是不一样的。例如{:a inc}这样一个字面量，在宏里是可以通过:a做求值的，然后这里得到的并非一个函数（function），而是一个符号（symbol）。再者，调试宏的时候你可能会被这样的结果困惑： &#40;defmacro a &#91;f&#93; &#40;println &#40;:a f&#41;&#41;&#41; &#40;a &#123;:a 1&#125;&#41; ; ==&#62; prints &#8230; <a href="http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Thread Macro是clojure里一个很强大的宏，他帮助你简化嵌套函数的调用，比如</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">str</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">inc</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">count</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">a</span> :<span style="color: #555;">b</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>就可以利用thread macro简写成</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">a</span> :<span style="color: #555;">b</span><span style="color: #66cc66;">&#93;</span> <span style="color: #b1b100;">count</span> <span style="color: #b1b100;">inc</span> <span style="color: #b1b100;">str</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>-&gt;&gt;和-&gt;类似，区别在于-&gt;&gt;把值作为函数的最后一个参数传入。</p>
<p>简单的功能介绍完了，接下来就遇到问题了。我需要功能，能够接受一个或多个函数，然后把这些函数组成一个pipeline。这时很自然想到-&gt;是一个好帮手。也许只需要一个类似这样的form就可以了： #(apply -&gt; % [funcs])。结果失败了，因为-&gt;是个宏，所以根本不能用apply。于是想到有apply-macro吗？有，或者说曾经有过。在contrib中曾经有一个apply-macro，不过被强烈不推荐使用。到这里，这条路堵死了，惟一的办法就是把-&gt;放到API之外，放到用户代码里去。</p>
<p>放到用户代码里，你需要写一个详细的说明文档并且告诉用户他必须这么做。然而在clojure世界里有一个更好的办法就是再写一个宏把-&gt;包装起来。这么做看似多此一举，其实是保持了API的一致性。通过宏，我们可以把自己的API延伸到用户代码中去。或者说，通过一个类似DSL的宏，给一些并不优雅的API一个缓冲，也为API日后的演化留下空间。</p>
<p>这里还要扯开一句关于宏的开发。clojure中所谓code is data，主要就是体现在宏里。原本在多数其他语言里，宏是不能求值的。但是在clojure里，由于code is data的缘故，宏是可以求值的。所有的输入数据都是list，你可以做first/reverse这样的操作。但是有一点要注意的是，宏中求得的值和代码里的值是不一样的。例如{:a inc}这样一个字面量，在宏里是可以通过:a做求值的，然后这里得到的并非一个函数（function），而是一个符号（symbol）。再者，调试宏的时候你可能会被这样的结果困惑：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defmacro</span> a <span style="color: #66cc66;">&#91;</span>f<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">a</span> f<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>a <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">; ==&gt; prints 1</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> b <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>a b<span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">; ==&gt; prints nil</span></div></div>
<p>字面量可以，同值的变量就不行了。原因还是那句，宏里不能求值。</p>
<p>继续谈-&gt;。这个宏其实远没有你想象的那么驯服。遇到复杂一点的情况：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">str</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>这个写法对吗？str是个函数，(get m :a)返回的是inc也是个函数，貌似正确。运行之后却报错get的参数数量错误。所以千万不要忘了-&gt;是个宏，(get m :a)这里是不会求值到inc的，直接作为一个list被宏吞下去。在宏里只能通过符号的组合变化来生成代码，那么一不小心，就没有inc什么事了。</p>
<p>于是，你可能想到这里需要一个确切的函数，就好比这样：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>也许这样就好多了，我们放了一个匿名函数，并不要求宏去求值，因为这个匿名函数会被宏生成到新的代码里。里面的get也会在运行时求值。看似没什么问题，可是一运行还是没有期待的结果，居然返回了一个匿名函数！而对这个匿名函数求值得到的也是一个错误的结果！简直有点无厘头了。</p>
<p>呵呵，不故弄玄虚了。我们用macroexpand看看发生了什么。</p>
<p>这是用匿名函数包装以前</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>get <span style="color: #cc66cc;">2</span> m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>-&gt;居然只是简单地把2放到了get这个form里面！</p>
<p>再看看用匿名函数包装后的结果</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>和刚才一样，2被放到了第一个form的第一个参数位置！得到的是一个非法的form。</p>
<p>那么既然-&gt;只是简单地把第一个参数放到后面form的首个参数的位置，那么这个宏正确的使用方法其实是</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>再加一层括号！</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>可见，-&gt;虽然是个功能强大的宏，但宏终归只是宏，和函数的区别是明显的。在使用的时候，不能完全按照函数的习惯。</p>
<p>如果你想了解实际的代码，可以参考slacker 0.3.0里的这个interceptor框架：<br />
<a href="https://github.com/sunng87/slacker/blob/master/src/slacker/interceptor.clj" target="_blank">https://github.com/sunng87/slacker/blob/master/src/slacker/interceptor.clj</a><br />
上面提到的难处，多半也都是在开发这个框架时亲身经历的。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Clojure RPC, prototyping and early thoughts</title>
		<link>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/</link>
		<comments>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 08:47:34 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[opensource]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1070</guid>
		<description><![CDATA[Last week, I prototyped an RPC framework, slacker, by clojure and for clojure. What I did ? Suppose you have a sets of clojure functions to expose. Define them under a namespace: &#40;ns slapi&#41; &#40;defn timestamp &#91;&#93; &#160; &#40;System/currentTimeMillis&#41;&#41; ;; &#8230; <a href="http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Last week, I prototyped an RPC framework, <a href="https://github.com/sunng87/slacker" target="_blank">slacker</a>, by clojure and for clojure. </p>
<h3>What I did ?</h3>
<p>Suppose you have a sets of clojure functions to expose. Define them under a namespace:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> slapi<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defn</span> timestamp <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>System<span style="color: #66cc66;">/</span>currentTimeMillis<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;">;; ...more functions</span></div></div>
<p>Expose the namespace with slacker server, on port 2104:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>server<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>start<span style="color: #66cc66;">-</span>slacker<span style="color: #66cc66;">-</span>server <span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'slapi<span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">2104</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>On the client side, we use the `defremote` macro to create a facade for `timestamp` function. This API will keep the client code consistent with local mode.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>client<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> sc <span style="color: #66cc66;">&#40;</span>slackerc <span style="color: #ff0000;">&quot;localhost&quot;</span> <span style="color: #cc66cc;">2104</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>defremote sc timestamp<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>timestamp<span style="color: #66cc66;">&#41;</span></div></div>
<p>Internally, slacker uses <a href="https://github.com/ztellman/aleph" target="_blank">aleph</a> for transport and <a href="https://github.com/revelytix/carbonite" target="_blank">carbonite</a> for serialization. I forked carbonite and made it compatible with clojure 1.2 because the aleph mainline is still running on 1.2. </p>
<h3>Going further</h3>
<h4>High-Order Functions</h4>
<p>In clojure, functions are treated as first class value. Within memory, you can pass function as parameter to another function. However, this is not supported by serialization framework. So is it possible to add support for that in future?</p>
<h4>Lazy sequence as parameter</h4>
<p>This is another interesting feature in clojure function call. You can pass a lazy-sequence to clojure function. In RPC, it requires parameters to be evaluated on the server side.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defn</span> get<span style="color: #66cc66;">-</span><span style="color: #b1b100;">first</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&amp;</span> args<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">first</span> args<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">apply</span> get<span style="color: #66cc66;">-</span><span style="color: #b1b100;">first</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">range</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Example copied from <a href="http://stackoverflow.com/q/8205446/371141" target="_blank">StackOverflow</a></p>
<h4>Coordinated states between several remote servers</h4>
<p>With RPC, we can update states on several servers. So do we need something like distributed dosync:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defremote a1 update<span style="color: #66cc66;">-</span>a1<span style="color: #66cc66;">-</span>state<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>defremote a2 update<span style="color: #66cc66;">-</span>a2<span style="color: #66cc66;">-</span>state<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>dosync<span style="color: #66cc66;">-</span>distributed<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>update<span style="color: #66cc66;">-</span>a1<span style="color: #66cc66;">-</span>state some<span style="color: #66cc66;">-</span>value<span style="color: #66cc66;">&#41;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>update<span style="color: #66cc66;">-</span>a2<span style="color: #66cc66;">-</span>state some<span style="color: #66cc66;">-</span>value<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>I&#8217;m not sure if this is a valid scenario in real world but I think it&#8217;s an interesting topic.(distributed STM?)</p>
<h3>Conclusion</h3>
<p>RPC is the first step to distributed clojure world. I will keep you updated with my prototype. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Spark in common lisp</title>
		<link>http://sunng.info/blog/2011/11/spark-in-common-lisp/</link>
		<comments>http://sunng.info/blog/2011/11/spark-in-common-lisp/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 06:26:09 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[lisp]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1068</guid>
		<description><![CDATA[还是关于spark的，一石激起千层浪，每个人心中都有一个spark。其实spark脚本刚出来的时候问题很多，但是就是因为产生了共鸣，众人拾柴pull request多。像redis的作者antirez也忍不住自己用c写了一个aspark。 说完了别人的，那么来看看我的：clspark，common-lisp的spark。原本是打算用clojure写，但是想到jvm的启动速度，把这个机会留给我的第一个common lisp程序吧。 其实很简单。 common lisp的核心库里没有split，所以这里从cl-cookbook拷贝了一个split的实现，坦白说我还看不太懂这个loop的写法。loop是common lisp中最尴尬的form，因为他的形式太多。这点在clojure中是不存在的。比较一下就能发现，在语言层面，clojure是相对现代得多的lisp方言。]]></description>
			<content:encoded><![CDATA[<p>还是关于spark的，一石激起千层浪，每个人心中都有一个spark。其实spark脚本刚出来的时候问题很多，但是就是因为产生了共鸣，众人拾柴pull request多。像redis的作者antirez也忍不住自己用c写了一个<a href="https://github.com/antirez/aspark" target="_blank">aspark</a>。</p>
<p>说完了别人的，那么来看看我的：clspark，common-lisp的spark。原本是打算用clojure写，但是想到jvm的启动速度，把这个机会留给我的第一个common lisp程序吧。</p>
<p><img src="http://i.imgur.com/oD7m4.png" alt="" /></p>
<p>其实很简单。<br />
<script src="https://gist.github.com/1375401.js"> </script></p>
<p>common lisp的核心库里没有split，所以这里从cl-cookbook拷贝了一个split的实现，坦白说我还看不太懂这个loop的写法。loop是common lisp中最尴尬的form，因为他的形式太多。这点在clojure中是不存在的。比较一下就能发现，在语言层面，clojure是相对现代得多的lisp方言。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/11/spark-in-common-lisp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Grails的核心依赖必须保证项目中版本一致！</title>
		<link>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/</link>
		<comments>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 14:51:43 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1037</guid>
		<description><![CDATA[好久没写语录式大标题了，实在是今天玩Grails受害很深很深。 Grails因为本身是通过ivy来管理依赖的，虽然后续的版本和maven的集成不断加深，但是本身还是通过ivy来解析pom.xml。也就是说最后的活还是ivy干的。如果你的项目比较大，选择了通过maven来管理项目，而你的依赖中又牵扯了很多其他的依赖，那么你危险了。 :: UNRESOLVED DEPENDENCIES :: :: log4j#log4j;1.2.16: configuration not found in log4j#log4j;1.2.16: &#8216;master&#8217;. It was required from &#8230;;1.7.0 runtime 对maven用户这是一条多么发指的报错！（比如这个） 它的原因其实是你的dependency中有!=1.2.16版本你的log4j，比如1.2.12，即使你在pom里将它添加到了exclusion中也没有用，必须要保持版本的一致！至于你用什么办法让他们保持一致，还是干脆放弃用maven管理你的grails项目：It&#8217;s up to you. 同样的问题还出现在其他核心依赖上，例如commons-pool。]]></description>
			<content:encoded><![CDATA[<p>好久没写语录式大标题了，实在是今天玩Grails受害很深很深。</p>
<p>Grails因为本身是通过ivy来管理依赖的，虽然后续的版本和maven的集成不断加深，但是本身还是通过ivy来解析pom.xml。也就是说最后的活还是ivy干的。如果你的项目比较大，选择了通过maven来管理项目，而你的依赖中又牵扯了很多其他的依赖，那么你危险了。</p>
<blockquote><p>:: UNRESOLVED DEPENDENCIES ::</p>
<p>:: log4j#log4j;1.2.16: configuration not found in log4j#log4j;1.2.16: &#8216;master&#8217;. It was required from &#8230;;1.7.0 runtime</p></blockquote>
<p>对maven用户这是一条多么发指的报错！（比如<a href="http://forum.springsource.org/showthread.php?104033-Can-not-load-a-log4J-library" target="_blank">这个</a>）</p>
<p>它的原因其实是你的dependency中有!=1.2.16版本你的log4j，比如1.2.12，即使你在pom里将它添加到了exclusion中也没有用，必须要保持版本的一致！至于你用什么办法让他们保持一致，还是干脆放弃用maven管理你的grails项目：It&#8217;s up to you.</p>
<p>同样的问题还出现在其他核心依赖上，例如commons-pool。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The distribution of intelligence</title>
		<link>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/</link>
		<comments>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 06:03:25 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[heatcanvas]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1027</guid>
		<description><![CDATA[This could be a big title for the content. I just work out a heat map based on the data of users who enrolled online courses offered by Stanford. (Click to enlarge) I think you already have your ideas about &#8230; <a href="http://sunng.info/blog/2011/10/the-distribution-of-intelligence/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This could be a big title for the content.</p>
<p>I just work out a heat map based on <a href="http://maps.google.com/maps/ms?ie=UTF&#038;msa=0&#038;msid=203716810039202316490.0004aeb1b1a01b1d3b9af" target="_blank">the data</a> of users who enrolled online courses offered by Stanford.</p>
<p><a href="http://imgur.com/rWUkH"><img src="http://i.imgur.com/rWUkH.png" width="500" alt="" title="Hosted by imgur.com" /></a><br />
(Click to enlarge)</p>
<p>I think you already have your ideas about this map. New England, California and Central Europe has higher density than any other area of the world. Also you can find some light in South America, East Coast Australia, India and China. I think this could be an overview of how intelligence distributed around the globe.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>GPS数据采集与OpenStreetMap编辑</title>
		<link>http://sunng.info/blog/2011/10/gps%e6%95%b0%e6%8d%ae%e9%87%87%e9%9b%86%e4%b8%8eopenstreetmap%e7%bc%96%e8%be%91/</link>
		<comments>http://sunng.info/blog/2011/10/gps%e6%95%b0%e6%8d%ae%e9%87%87%e9%9b%86%e4%b8%8eopenstreetmap%e7%bc%96%e8%be%91/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 03:17:48 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[OpenStreetMap]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1018</guid>
		<description><![CDATA[简单介绍一下通过GPS采集道路数据并上传到OpenStreetMap的流程。 采集 首先你需要一个GPS数据记录器，或者叫做GPS Logger。这类产品在淘宝上可以找到很多，台湾的长天(HOLUX)是相对价廉物美的品牌。我的设备是HOLUX m1000c，下文以此为例。 m1000c的使用非常简单。开机之后，指示GPS的黄灯点亮，设备开始搜索GPS卫星。根据你所出的位置、遮挡情况以及天气情况，搜星的时间略有不同。当GPS黄灯开始闪烁时Logger即开始记录数据，默认情况下m1000c每隔5秒记录一次数据。每次重启后，Logger都会新开一条记录。 导入 对Windows用户，将Logger通过USB线与电脑连接后，可以利用随机附带的软件将数据导入为GPX格式。对Linux用户，可以利用gpsbabel导入数据： gpsbabel -t -i m241 -f /dev/ttyACM0 -o gpx -F myfile.gpx 其中： -t 表示数据为track类型 -i m241 输入格式为HOLUX m241，m1000c使用的是这种格式 -f /dev/ttyACM0 输入设备是/dev/ttyACM0 -o gpx 输出格式是gpx -F 输出文件myfile.gpx 在一些发行版上，需要root权限访问/dev/ttyACM0，所以不要忘记将输出的文件chown给普通用户。 导入完成后可以利用下面的命令清空Logger gpsbabel -i m241,erase_only=1 -f /dev/ttyACM0 &#8230; <a href="http://sunng.info/blog/2011/10/gps%e6%95%b0%e6%8d%ae%e9%87%87%e9%9b%86%e4%b8%8eopenstreetmap%e7%bc%96%e8%be%91/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>简单介绍一下通过GPS采集道路数据并上传到OpenStreetMap的流程。</p>
<h3>采集</h3>
<p>首先你需要一个GPS数据记录器，或者叫做GPS Logger。这类产品在淘宝上可以找到很多，台湾的长天(HOLUX)是相对价廉物美的品牌。我的设备是HOLUX m1000c，下文以此为例。</p>
<p>m1000c的使用非常简单。开机之后，指示GPS的黄灯点亮，设备开始搜索GPS卫星。根据你所出的位置、遮挡情况以及天气情况，搜星的时间略有不同。当GPS黄灯开始闪烁时Logger即开始记录数据，默认情况下m1000c每隔5秒记录一次数据。每次重启后，Logger都会新开一条记录。</p>
<h3>导入</h3>
<p>对Windows用户，将Logger通过USB线与电脑连接后，可以利用随机附带的软件将数据导入为GPX格式。对Linux用户，可以利用<a href="http://www.gpsbabel.org/" target="_blank">gpsbabel</a>导入数据：<br />
<em>gpsbabel -t -i m241 -f /dev/ttyACM0 -o gpx -F myfile.gpx</em></p>
<p>其中：</p>
<ul>
<li>-t 表示数据为track类型</li>
<li>-i m241 输入格式为HOLUX m241，m1000c使用的是这种格式</li>
<li>-f /dev/ttyACM0 输入设备是/dev/ttyACM0</li>
<li>-o gpx 输出格式是gpx</li>
<li>-F 输出文件myfile.gpx</li>
</ul>
<p>在一些发行版上，需要root权限访问/dev/ttyACM0，所以不要忘记将输出的文件chown给普通用户。</p>
<p>导入完成后可以利用下面的命令清空Logger<br />
<em>gpsbabel -i m241,erase_only=1 -f /dev/ttyACM0</em></p>
<p>在Windows和Linux上都可以使用<a href="http://sourceforge.net/apps/mediawiki/viking/index.php?title=Main_Page" target="_blank">Viking</a>查看导入的数据：</p>
<ul>
<li>启动viking</li>
<li>添加一个OSM地图图层： Layers->New Map Layer</li>
<li>导入GPX数据： File->Append File&#8230;</li>
<li>下载OSM地图，右键点击左侧的Map图层，Download Missing Onscreen Maps</li>
</ul>
<p><a href="http://www.flickr.com/photos/40741608@N08/6213079184/" title="Screenshot at 2011-10-05 09:45:20 by 贝小塔, on Flickr"><img src="http://farm7.static.flickr.com/6103/6213079184_f653ca2ca6.jpg" width="500" height="387" alt="Screenshot at 2011-10-05 09:45:20"></a></p>
<h3>编辑</h3>
<p>Windows和Linux用户都可以通过<a href="http://merkaartor.be/" target="_blank">Merkaartor</a>编辑OSM数据。</p>
<p>启动Merkaartor，导入GPS数据： File->Import。<br />
选择左侧的GPS图层，对需要导入的数据，右键点击Extract Drawing Layer将GPS转换为可编辑数据。<br />
<a href="http://www.flickr.com/photos/40741608@N08/6213247680/" title="Screenshot at 2011-10-05 10:57:17 by 贝小塔, on Flickr"><img src="http://farm7.static.flickr.com/6167/6213247680_046e360c63.jpg" width="500" height="303" alt="Screenshot at 2011-10-05 10:57:17"></a></p>
<p>根据实际情况编辑道路数据的属性。对GPS转换的数据，选择菜单Feature->Force Upload，将其加入dirty set准备上传。点击Upload即可将数据上传到OpenStreetMap。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/gps%e6%95%b0%e6%8d%ae%e9%87%87%e9%9b%86%e4%b8%8eopenstreetmap%e7%bc%96%e8%be%91/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Google closure library with ClojureScript</title>
		<link>http://sunng.info/blog/2011/08/using-google-closure-library-with-clojurescript/</link>
		<comments>http://sunng.info/blog/2011/08/using-google-closure-library-with-clojurescript/#comments</comments>
		<pubDate>Fri, 05 Aug 2011 12:04:02 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[clojurescript]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=956</guid>
		<description><![CDATA[Google closure library is shipped with ClojureScript, and could be compiled with ClojureScript into a minimized javascript file. So closure library is doubtlessly the first candidate when you are considering to use an external Javascript library in your cljs browser &#8230; <a href="http://sunng.info/blog/2011/08/using-google-closure-library-with-clojurescript/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Google closure library is shipped with ClojureScript, and could be compiled with ClojureScript into a minimized javascript file. So closure library is doubtlessly the first candidate when you are considering to use an external Javascript library in your cljs browser application.</p>
<p>However, different from clojure&#8217;s interoperability with Java, ClojureScript has its own characteristics when you are interoperating with JavaScript and JavaScript based libraries.</p>
<p><strong>Clojure types are not fully compatible with JavaScript types</strong><br />
In ClojureScript, you can never treat a Clojure map as a JavaScript object although they have similar characteristics. You have to do some conversion before passing a clojure map to javascript functions. Matthew Gilliard made <a href="https://gist.github.com/1098417#file_ajax.cljs" target="_blank">a sample</a> of such conversion.</p>
<p><strong>JavaScript package is not Clojure namespace</strong><br />
This could be a common mistake for ClojureScript newbie. Actually, JavaScript doesn&#8217;t have concept of &#8220;Package&#8221; or &#8220;Namespace&#8221;. Many JavaScript libraries(dojo, Google Closure) made enhancement on this. ClojureScript also takes advantage of this mechanism. So before you start to coding with closure, you may browse <a href="http://closure-library.googlecode.com/svn/docs/index.html" target="_blank">closure library API document</a>, and find a module called <em>goog.net</em> which includes lots of types. Then you write this:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> myjs<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">require</span> <span style="color: #66cc66;">&#91;</span>goog<span style="color: #66cc66;">.</span>net :<span style="color: #555;">as</span> gnet<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>But compiler shows you &#8220;ERROR: JSC_MISSING_PROVIDE_ERROR. required &#8220;goog.net&#8221; namespace never<br />
provided at &#8230; &#8220;. This is not a PATH issue. The root cause is that closure module has a lower granularity than Clojure ones. Types are often contained in their own modules. You can find closure source code in <em>clojurescript/closure/library/closure</em>. Modules are declare with <em>goog.provide</em> function. Thus, you should require this name instead of the logical module name.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> myjs<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">require</span> <span style="color: #66cc66;">&#91;</span>goog<span style="color: #66cc66;">.</span>net<span style="color: #66cc66;">.</span>XhrIo :<span style="color: #555;">as</span> gxhr<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>In addition, ClojureScript does not support &#8216;use&#8217;.</p>
<p><strong>Just use full name for JavaScript class</strong><br />
For functions contains in some module, you can refer it with the clojure way:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> myjs<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">require</span> <span style="color: #66cc66;">&#91;</span>goog<span style="color: #66cc66;">.</span>dom :<span style="color: #555;">as</span> dom<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>dom<span style="color: #66cc66;">/</span>$ <span style="color: #ff0000;">&quot;element-id&quot;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>But for classes, just use the full name and ignore the module alias.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> myjs<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">require</span> <span style="color: #66cc66;">&#91;</span>goog<span style="color: #66cc66;">.</span>net<span style="color: #66cc66;">.</span>XhrIo :<span style="color: #555;">as</span> gxhr<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> xhr <span style="color: #66cc66;">&#40;</span>goog<span style="color: #66cc66;">.</span>net<span style="color: #66cc66;">.</span>XhrIo<span style="color: #66cc66;">.</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>These are basic tips before you start using Closure with ClojureScript. Leveraging on Google&#8217;s closure library, you can create cross-browser JavaScript application with Clojure easily.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/08/using-google-closure-library-with-clojurescript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ClojureScript Recipes</title>
		<link>http://sunng.info/blog/2011/07/clojurescript-recipes/</link>
		<comments>http://sunng.info/blog/2011/07/clojurescript-recipes/#comments</comments>
		<pubDate>Sun, 24 Jul 2011 08:29:06 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure javascript]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=926</guid>
		<description><![CDATA[一周前左右有人说javascript是assembly language for the web, 结果一周不到clojurescript发布了。闹了半天clojure 1.3迟迟不发布是因为effort都迫不及待地转移到向javascript迁移上去了。简单地说cljs是clojure在javascript上的实现，通过cljsc可以把clojure编译成js，运行在浏览器里或是Node环境里。 目前clojurescript还没有正式的发布版本，需要从github签出开发版本。 cljs是在Oracle JDK上开发的，引用了sun.org.mozilla.javascript.internal.Context，这个类在OpenJDK里叫做sun.org.mozilla.javascript.Context。所以没有办法，暂时只能在Oracle JDK上用clojurescript。 cljs自带的所有脚本，启动jvm时，heap size都是开2G的。可怜我所有的内存才2.5G，还是分布在两台电脑上（#@&#38;*……@￥@！）。不过我手动把它改为512M后cljsc还是依然可以正常运行的。 cljs与javascript的互操作是最麻烦的部分，一般情况cljs通过(js*)这个form来访问javascript数据和对象，比如访问document：(js* &#8220;document&#8221;)。进而访问getElementById时，即(.getElementById (js* &#8220;document&#8221;) &#8220;some-id&#8221;)。 cljs访问js对象时，通过(aget)而不是(.属性名)，例如(aget rage &#8220;ups&#8221;)编译后为rage.ups，如果(.ups rage)就会被当作函数调用。不过奇怪的是如果(.title rage)依然会被编译成rage.title。这种不一致的情况在对.url也存在。当然用aget是可以获得一致的结果的（aget在clojure里是根据索引取java数组的form，在cljs里可以支持js object了）。 当访问无参数的js对象时，cljs与clojure有不同。例如在clojure里(.toString date)，而在cljs里，这样写编译的结果是date.toString，注意没有括号，直接访问这个function对象了。所以在cljs里，正确的写法有些变化(. date (toString))。 创建js对象，可以通过(js-obj)这个form 修改dom属性，需要用(set!)这个form，如 (set! (.src img) &#8220;http://xxx&#8221;)。如果把cljs用在网页里，类似这样的操作比比皆是，这和clojure大不相同。 cljs里没有STM，暂时也不支持ref。可以直接用def定义变量，随意地访问和修改，js环境是单线程环境。 对于要对外访问的方法，在声明时加上^:export可以让编译器不修改方法的名字。 用cljs开发有趣归有趣，调试还是很困难的，建议开发的时候就写好打log的代码(js* &#8220;console.log&#8221;)，因为目前cljsc编译的速度也不快，反复地修改代价还是挺高的。当然，为了cool，以上都不是问题。]]></description>
			<content:encoded><![CDATA[<p>一周前左右有人说javascript是assembly language for the web, 结果一周不到clojurescript发布了。闹了半天clojure 1.3迟迟不发布是因为effort都迫不及待地转移到向javascript迁移上去了。简单地说cljs是clojure在javascript上的实现，通过cljsc可以把clojure编译成js，运行在浏览器里或是Node环境里。</p>
<p>目前clojurescript还没有正式的发布版本，需要从github签出开发版本。</p>
<ol>
<li>cljs是在Oracle JDK上开发的，引用了sun.org.mozilla.javascript.internal.Context，这个类在OpenJDK里叫做sun.org.mozilla.javascript.Context。所以没有办法，暂时只能在Oracle JDK上用clojurescript。</li>
<li>cljs自带的所有脚本，启动jvm时，heap size都是开2G的。可怜我所有的内存才2.5G，还是分布在两台电脑上（#@&amp;*……@￥@！）。不过我手动把它改为512M后cljsc还是依然可以正常运行的。</li>
<li>cljs与javascript的互操作是最麻烦的部分，一般情况cljs通过(js*)这个form来访问javascript数据和对象，比如访问document：(js* &#8220;document&#8221;)。进而访问getElementById时，即(.getElementById (js* &#8220;document&#8221;) &#8220;some-id&#8221;)。</li>
<li>cljs访问js对象时，通过(aget)而不是(.属性名)，例如(aget rage &#8220;ups&#8221;)编译后为rage.ups，如果(.ups rage)就会被当作函数调用。不过奇怪的是如果(.title rage)依然会被编译成rage.title。这种不一致的情况在对.url也存在。当然用aget是可以获得一致的结果的（aget在clojure里是根据索引取java数组的form，在cljs里可以支持js object了）。</li>
<li>当访问无参数的js对象时，cljs与clojure有不同。例如在clojure里(.toString date)，而在cljs里，这样写编译的结果是date.toString，注意没有括号，直接访问这个function对象了。所以在cljs里，正确的写法有些变化(. date (toString))。</li>
<li>创建js对象，可以通过(js-obj)这个form</li>
<li>修改dom属性，需要用(set!)这个form，如 (set! (.src img) &#8220;http://xxx&#8221;)。如果把cljs用在网页里，类似这样的操作比比皆是，这和clojure大不相同。</li>
<li>cljs里没有STM，暂时也不支持ref。可以直接用def定义变量，随意地访问和修改，js环境是单线程环境。</li>
<li>对于要对外访问的方法，在声明时加上^:export可以让编译器不修改方法的名字。</li>
</ol>
<p>用cljs开发有趣归有趣，调试还是很困难的，建议开发的时候就写好打log的代码(js* &#8220;console.log&#8221;)，因为目前cljsc编译的速度也不快，反复地修改代价还是挺高的。当然，为了cool，以上都不是问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/07/clojurescript-recipes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>使用defrecord与defprotocol的注意事项</title>
		<link>http://sunng.info/blog/2011/07/%e4%bd%bf%e7%94%a8defrecord%e4%b8%8edefprotocol%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/</link>
		<comments>http://sunng.info/blog/2011/07/%e4%bd%bf%e7%94%a8defrecord%e4%b8%8edefprotocol%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 02:06:03 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=922</guid>
		<description><![CDATA[简单地说，protocol是clojure中的接口，record是clojure中的数据类型。 可以通过这样的code定义一个protocol &#40;defprotoco DummyProtocol &#160; &#34;doc string...&#34; &#160; &#40;method-one &#91;self x&#93; &#34;doc string...&#34;&#41;&#41; 需要注意的是，protocol里所有方法的第一个参数都是self/this参数（类似python），从第二个开始才是调用时传入的参数。如果方法要重载呢？ &#40;defprotocol DummyProtocol &#160; &#34;doc string...&#34; &#160; &#40;method-one &#91;self x&#93; &#91;self x y&#93; &#34;doc string&#34;&#41; &#41; Apress的 Practical Clojure 书里的例子，给重载的参数表加上了括号，这样会导致编译错误（注记）。 定义一个record实现protocol (defrecord DummyRecord [a b c] &#160; &#8230; <a href="http://sunng.info/blog/2011/07/%e4%bd%bf%e7%94%a8defrecord%e4%b8%8edefprotocol%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>简单地说，protocol是clojure中的接口，record是clojure中的数据类型。</p>
<p>可以通过这样的code定义一个protocol</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defprotoco DummyProtocol<br />
&nbsp; <span style="color: #ff0000;">&quot;doc string...&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>method<span style="color: #66cc66;">-</span>one <span style="color: #66cc66;">&#91;</span>self x<span style="color: #66cc66;">&#93;</span> <span style="color: #ff0000;">&quot;doc string...&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>需要注意的是，protocol里所有方法的第一个参数都是self/this参数（类似python），从第二个开始才是调用时传入的参数。如果方法要重载呢？</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defprotocol DummyProtocol<br />
&nbsp; <span style="color: #ff0000;">&quot;doc string...&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>method<span style="color: #66cc66;">-</span>one <span style="color: #66cc66;">&#91;</span>self x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#91;</span>self x y<span style="color: #66cc66;">&#93;</span> <span style="color: #ff0000;">&quot;doc string&quot;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#41;</span></div></div>
<p>Apress的 Practical Clojure 书里的例子，给重载的参数表加上了括号，这样会导致编译错误（<a href="http://book.douban.com/annotation/13819191/" target="_blank">注记</a>）。</p>
<p>定义一个record实现protocol</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">(defrecord DummyRecord [a b c]<br />
&nbsp; DummyProtocol<br />
&nbsp; (method-one [self x] (+ a x))<br />
&nbsp; (method-one [self x y] (+ a x y)))</div></div>
<p>Practical Clojure里关于这部分的代码，又丢掉了self参数（<a href="http://book.douban.com/annotation/13819264/" target="_blank">注记</a>）。</p>
<p>最后还有一个问题，如果直接use你的ns，你会发现调用record时出现：<br />
java.lang.IllegalArgumentException: Unable to resolve classname: DummyRecord</p>
<p>怎么回事，不是都use了吗？原因是record被编译成了java对象，所以引用时要用java对象的引用方式，import之。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/07/%e4%bd%bf%e7%94%a8defrecord%e4%b8%8edefprotocol%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

