Skip to content

Instantly share code, notes, and snippets.

@skandhas
Forked from hooopo/ns
Created May 8, 2012 12:12
Show Gist options
  • Save skandhas/2634504 to your computer and use it in GitHub Desktop.
Save skandhas/2634504 to your computer and use it in GitHub Desktop.
ns
有人用过cell么?
<span style="font-size: small;"><a target="_blank" href="http://rubyforge.org/frs/?group_id=2978&amp;release_id=9650">http://rubyforge.org/frs/?group_id=2978&amp;release_id=9650</a>
<br /></span>
<br /><span style="font-size: small;"> </span>
<br /><span style="font-size: small;">
<br />非常小,源代码一目了然。感觉虽然有点土,但比自己做个module的方式好一点点
<br />号称: 代替发挥component作用的controller, 这样就不需要邪恶的render_component了
<br /></span>
<br /><span style="font-size: small;">A cell acts as a lightweight controller in the sense that it will assign variables and render a view.</span>
<br /><span style="font-size: small;"> </span>
<br /><span style="font-size: small;">cell可以用session, params, request等方法访问 父控制器的对应参量
<br /></span>
<br /><span style="font-size: small;">但其它局部变量和实例变量 默认不会传到cell里面</span>
<br /><span style="font-size: small;">The controller's instance variables and params hash are not directly available from the cell or its views. </span>
<br /><span style="font-size: small;"> </span>
<br /><span style="font-size: small;">目录结构:</span>
<br /><pre name="code" class="java">app/
models/
views/
helpers/
controllers/
cells/
my_cell.rb #cell 'controller'
my_cell/ #cell 'views'
show.html.erb
...</pre><span style="font-size: small;">cell可以用application helper,若要使用其他helper需声明,如:</span><pre name="code" class="ruby">class ShoppingCartCell &lt; Cell::Base
helper :product
....
end</pre> <span style="font-size: small;">使用:</span><pre name="code" class="ruby">&lt;%= render_cell :my_cell, :show %&gt;</pre>
<br /><span style="font-size: small;">
<br /></span>
<br />
<br /><span style="font-size: small;">=======================邪恶的component回顾=========================</span>
<br /><span style="font-size: small;"> </span>
<br /><span style="font-size: small;">component 组装页面的使用方式大致如下:</span>
<br /><pre name="code" class="ruby">render_component :controller=&gt;..., :action=&gt;..., :params=&gt;{...}</pre>
<br /><span style="font-size: small;">rails似乎没有提供以path/url作component的方式,所以只好用</span>
<br /><pre name="code" class="ruby">render_component ( ActionController::Routing::Routes.recognize_path("/some/action") ) #how ugly!</pre>
<br /><span style="font-size: small;">想要包含外部页面为组件,其中一个办法是用esi:include标签。。。</span>
<br /><span style="font-size: small;">只有用render_component才能调用其他action及action之上的过滤器并包含其结果,而且很慢 ...</span>
<br />
为什么人们说Ruby是个异类
<p>rt.<br>
经过一番思考,我觉得有如下答案:</p>
<ol>
<li>
Ruby是面向人类的语言,其他语言却很少这样考虑。</li>
<li>
Ruby社区歧视Windows用户……</li>
</ol>
<p> </p>
<p><span style="color: #800080;">语法糖</span>
是经常被说奇怪的部分,也是新语言里经常带入的东西。</p>
<p>但是纵观很多语言,有的是完全反对,有的是简单代入——它们没有深刻思考这一问题。</p>
<p>Ruby语法糖不仅仅是写起来更短那么简单:</p>
<ul>
<li>它是在简单的通用规则上达成的:函数调用可以省略括号,函数名可以包含符号 —— 与其说它是规则,不如说它去掉了这两个规则:函数调用必须包含括号,函数名不能包含符号。</li>
<li>它是从自然语言出发的,更短但是读起来不明白的糖是不推荐的。</li>
</ul>
<p>所以Ruby的糖衣化的语句往往有两种读法:一是自然语言的抽象理解,一是具体的实现。</p>
<p>相比之下,Scala就显得是为糖而糖了,如下面的语句,仅仅为了省略一组{}就引入了一个局部语法规则:</p>
<pre name="code" class="Scala">args.foreach(arg =&gt; greeting += (arg + " "))</pre>
<p><span style="color: #3366ff;">2009年5月10日补充: </span>
</p>
<p><span style="color: #3366ff;">现在看来,scala 的这个语句不是糖: arg =&gt; ... 只是给了个匿名函数。</span>
</p>
<p><span style="color: #3366ff;">所以相比还是 ruby 更甜……(给匿名函数可以 {} 可以 do..end 可以 &amp;proc 可以 &amp;:symbol)</span></p>
<p> </p>
<p><span style="color: #800080;">end</span>
是经常被批评的部分,为什么Ruby用end结束块呢?</p>
<p>C和类C语言用'}' ,可是这个读起来拗口, 右大括号? close curlin ?</p>
<p>lisp和类lisp用')' ,读起来可以简单点,右括号或者ket,但是对于支持指令式编程的语言来说,用圆括号定义块容易混淆。</p>
<p>python省掉了这个,但代价就是空白字符——缩进也成为语法的一部分了。</p>
<p>哪一种更好,与用户习惯有关,如果你玩了几年C或者Java,自然就觉得end很奇异。</p>
<p>但是对于一个没有被先入为主影响的人,end是最浅显、最好读、最容易理解的……</p>
<p>譬如用end的BASIC就是简单易学到堪称脑残。</p>
<p> </p>
<p> </p>
<p>对没接触过程序设计的人,Ruby绝对比C,C++,Java,C#,Haskell容易学得多。但是,这类人经常是Windows用户,所以……很多人说Ruby学习难度高(不如说linux学习难度高吧……)</p>
给ruby实现汇编inline
<p>最近正在考虑给Ruby写个运行时<span style="color: #333399;">从汇编语言</span>
生成字节码的扩展。比<span style="color: #ff0000;">JIT</span>
更牛哦。</p>
<p> </p>
<p>原理:在C里面调用_asm call</p>
<pre name="code" class="c">BYTE buf[1024];
DWORD by = (DWORD)buf;
...
_asm call by
</pre>
<p> </p>
<p>思路:首先把字符串翻译成机器码,然后将机器码传给一个函数,这个函数大致上是这样</p>
<pre name="code" class="c">VALUE run_bytecode(VALUE self, VALUE code) {
DWORD buf = (DWORD)(StringValueCstr(code));
_asm call buf
return Qnil;
}</pre>
<p> </p>
<p>参考待读:</p>
<p>这里应该能找到不少有用的东西。</p>
<p>http://webster.cs.ucr.edu/AsmTools/RollYourOwn/index.html</p>
<p> </p>
<p>这个家伙写了20篇blog,完全用Ruby实现了汇编DSL,剩下的就是指令-&gt;字节码和算地址了。</p>
<p>http://www.hokstad.com/compiler</p>
Ruby 1.9: 中文编程
<p>突然想起,Ruby 1.9支持中文方法名和变量名!</p>
<p> </p>
<pre name="code" class="ruby">def 召唤 家丁
case 家丁
when '阿福', '旺财'
puts "……少爷,我系#{家丁}……"
else
puts '……(一段短短的沉默,然后一段长长的沉默)'
end
end
家丁甲, 家丁乙 = %w[阿福 旺财]
召唤 家丁甲</pre>
<p> </p>
<p>哼哼,我们可以改造黄瓜或者阿死别克了</p>
<p> </p>
<pre name="code" class="ruby">alias 龙门阵 Story
alias 角色扮演 Scenario
alias 假设 Given
alias 当 When
alias 而且 And
alias 于是 Then</pre>
<p> </p>
<p>不过还是有些限制,类和模块不能用中文名打头(开头加上大写字母还是可以的)</p>
<p> </p>
<pre name="code" class="ruby">class 家丁
end
#=&gt;error: class/module name must be CONSTANT
class Q宝宝
end
#ok</pre>
<p> </p>
<p>观众可能会问: if then 怎么整?先想想,大致用法应该是这样吧</p>
 
<pre name="code" class="ruby">如果 女的, 那么{问三围}, 否则{讲再见} </pre>
 
<p>实现起来,我们可以定义如果-那么-否则如下</p>
<p> </p>
<pre name="code" class="ruby">def 那么 &amp;块
end
def 否则 &amp;块
end
def 如果 条件, 真块, 假块=-&gt;(){nil}
条件 ? 真块.call : 假块.call
end</pre>
<p> 试一试</p>
<p> </p>
<pre name="code" class="ruby">def 问三围
puts '小……小柠檬?!小蜜瓜?!不想活了?!'
end
def 讲再见
puts '不是讲好一小时见血任做吗?你跑不掉的……hehehe……'
end
[true, false].each {|女的|
如果 女的, 那么{问三围}, 否则{讲再见}
}
</pre>
<p> </p>
<p> 继续汉化def——很简单</p>
<p> </p>
<pre name="code" class="ruby">alias 定义 define_method</pre>
<p> </p>
<p>文章太长不好,就此打住~</p>
<p> </p>
<p>参考文献:</p>
<p>《窈窕淑女》,《零之使魔》,《买凶拍人》</p>
warm和fuzzy \( ` △ ' )/
<p>受RednaxelaFX mm启发,修改产生了这么个东西: WFT(变种warm, fuzzy thing)</p>
<p> </p>
<p>warm也可看作return或者unit或者wrap,fuzzy也可看作bind或者pass。</p>
<p> </p>
<pre name="code" class="ruby">class WFT
  attr_reader :value
def initialize object
@value = (object.is_a? WFT) ? object.value : object
end
def fuzzy
WFT.new(yield @value)
end
def WFT.warm object
WFT.new object
end
end</pre>
<p> </p>
<p>它可以和object互相转换: </p>
<ul>
<li>WFT.warm object  #=&gt;  wft</li>
<li>wft.value  #=&gt;  object<br />
</li>
</ul>
<p>它满足四条定律(Monad?才……才不是Monad呢!毛毛律真微妙):</p>
<ul>
<li>暖暖律: WFT.warm(wft)  ==  wft</li>
<li>暖毛律: WFT.warm(object).fuzzy(f)  ==  WFT.warm(f(object))</li>
<li>毛暖律: wft.fuzzy(WFT.warm)  ==  wft</li>
<li>毛毛律: wft.fuzzy(f).fuzzy(g)  ==  wft.fuzzy(g(f))</li>
</ul>
<p> </p>
<p>它有什么用呢?嗯…… 可以改变运算顺序。</p>
<p>例如设 f(x) = x * x, g(x) = x + x, h(x) = x - 2,则h(g(f(12)))可以写成:</p>
<pre name="code" class="ruby">WFT.
warm(12).
fuzzy{|x|x * x}.
fuzzy{|x|x + x}.
fuzzy{|x|x - 2}
</pre>
<p> </p>
<p>或者:</p>
<pre name="code" class="ruby">[f,g,h].inject WFT.warm(12) do |acc, func|
acc.fuzzy{|x| func.(x)}
end.value</pre>
<p> </p>
<p>这好像有点自己找罪受诶,看看:</p>
<pre name="code" class="ruby">[f,g,h].inject 12 do |acc, func|
func.(acc)
end</pre>
<p> </p>
<p>不过好处还是有的……吧?</p>
<p>当你手写一个超级变态巨大复合运算的时候,机器不会嚷嚷"stack level too deep"(手写8000多层也太难了吧!)。</p>
<p>也可以消灭end和')'队形(这不就是传说中的恶趣味吗?)。</p>
<p>比较WFT和Monad,Monad通过手动包装,保持了上下文,WFT自动包装把上下文都毁了。</p>
<p>结果……只是栈变成了队列而已吗??</p>
<p> </p>
<p> </p>
<p>既然有WFT,那么也能造个FWT出来,唔……我认为它是个蒜子(Onion)。</p>
<p> </p>
<pre name="code" class="ruby">class FWT
def initialize arr=[]
raise 'wtf r u doing?' unless arr.respond_to? :each
@seq = [] #function sequence
arr.each do |f|
if f.respond_to? :call
@seq &lt;&lt; f
else
raise 'again, wtf r u doing?'
end
end
end
def fuzzy &amp;block
  @seq &lt;&lt; block
self
end
def warm object
@seq.inject object do |acc, f|
f.(acc)
end
end
end</pre>
<p> </p>
<p>用法:</p>
<pre name="code" class="ruby">FWT.new.
fuzzy{|x|x*x}.
fuzzy{|x|x+x}.
fuzzy{|x|x-2}.
warm 12</pre>
 
<p>对纯洁的函数(与IO没联系而且不会污染环境),似乎能搞一些定理、归约什么的,不过 that's another story...</p>
<p> </p>
<p>但我大约似乎肯定还是听到卤比sama在对摸哪的说:你不是我的那杯茶……</p>
sorakake 机体设定
【colony】
<br />
<br /><img src="http://www.sorakake.net/tech/img/colony_l.jpg" />
<br />
<br />
<br />colony 比例对照:
<br />
<br /><img src="http://www.sorakake.net/tech/img/colony2_s.jpg" />
<br />
<br />
<br />【QT-arms系列】
<br />
<br />秋叶:
<br /><img src="http://www.sorakake.net/tech/img/qt01_img.jpg" />
<br /><img src="http://www.sorakake.net/tech/img/qt01_b.jpg" />
<br />
<br />五月:
<br /><img src="http://www.sorakake.net/tech/img/qt02_img.jpg" />
<br />
<br />ほのか(各种翻译都拗口……):
<br /><img src="http://www.sorakake.net/tech/img/qt03_img.jpg" />
<br />
<br />二姐:
<br /><img src="http://www.sorakake.net/tech/img/qt04_img.jpg" />
<br />
<br />
<br />妹子的手办真想买一个……
<br /><img src="http://www.sorakake.net/goods/img/figure002.png" />
<br />
<br />官方HP站:
<br /><a target="_blank" href="http://www.sorakake.net/home.html">http://www.sorakake.net/home.html</a>
<br />
萌语言
系统需求:Ruby 1.9
<br />运行环境编码:GBK
<br />
<br />解释器moe.rb(请保存为utf-8格式)
<br /><pre name="code" class="ruby">
#encoding=utf-8
def 说 s
puts s.encode('gbk')
end
class String
def 萌
self.encode! 'utf-8'
[
'都', '.each ',
'做', ' do',
'酱', '","',
'~', "\r\n",
'喵', "\nend\n",
'哩', '"',
'咪', '{',
'叭', '}',
'咦', '(',
'哈', ')',
'咕', '[',
'咚', ']',
'呼', '|',
'说', '说 '
].each_slice 2 do |k,v|
self.gsub! k, v
end
eval self
end
end
while instr = (gets gets)
instr.sub! /\n.+?\n$/m, ''
instr.萌
end
</pre>
<br />
<br />运行(按Ctrl+Z可以退出)
<br /><pre name="code" class="命令行">
ruby moe.rb
</pre>
<br />
<br />萌语言的输入是here doc结构,第一行和最后一行必须相同。
<br />Hello World:
<br /><pre name="code" class="萌">
咕哩苹果酱香蕉哩咚都做呼果呼~说果喵
</pre>
<br />
<br />to do: 完善语法。
<br />
<br />未完待续……
萌语法(1)
写正规点的解释器之前,首先对萌语法进行一些设计
<br />
<br />下面一些东西是想到哪写到哪……
<br />
<br />1:<strong>是..就..不..喵</strong>
<br />控制结构,相当if then else end
<br />
<br />2:<strong>晕..呜..喵</strong>
<br />循环结构,无限循环,通过呜跳出。
<br />控制+循环示例:
<br /><pre name="code" class="萌">
晕是你就怪不呜喵喵
</pre>
<br />
<br />3:<strong>噗..噜..噜..噜..喵</strong>
<br />在数学上,我们常常从旧集合出发定义新集合,如{2x|x∈Z, x&gt;0},在萌语言中,我们可以这样写:
<br /><pre name="code" class="萌">
噗Z噜x噜x&gt;0噜2x喵
</pre>
<br />
<br />4:自由语境
<br />萌语言可以自由切换语境(Context,上下文),切换方法是行首/末空白
<br />纯空白行:建造新语境并代替该行对应的语境号
<br />[Tab]开头的行首空白表示往前n个语境
<br />[Tab]开头的行末空白表示往下n个语境
<br />[Space]开头的行首空白表示第n个语境
<br />[Space]开头的行末空白表示倒数第n个语境
<br />如果行首行末都有空白,则中间的内容被忽略(注释行)
<br />
<br />上面的n为二进制数,由[Tab]和[Space]表示
<br />[Tab]代表1,[Space]代表0
<br />
<br />表述有点不清晰……以后再改。
<br />
萌语言标准库:图形处理
使用<strong>嘣嘣</strong>语句可以定义一段动画,每两帧之间用一个空行隔开。
<br />
<br />举例如下:(摘自某人对破刃之剑某场景的解释)
<br /><pre name="code" class="萌">
嘣嘣
     ○ノ    \ ノ
      ノ\_・' ヽ /
       └    ○ヽ
                    ○ 、          ○
                三   /=>          ̄l □
                  /&gt; ´           く\
   .&lt; i~      ○ < キター
 丶 /   /\_ノ|丶
  ○ ̄      〈\
  ┃  | |
    ○  | |
\○, )\
 /   / ∠
〈〈
    _
   / /
 .'; /∨
○ノ  ◇ ○   ○
 \  へ~/  ̄ ヽノ|凹
  />   &gt;    Λ
            ○  /
       ○    く |L |
      /|V    /7/
    メ /&gt;~~`  √
     ○_
     &lt;\へ
         ̄ ミ    /
       ○   ミ   |
      /|V       /
    メ /&gt;~~`  √
     ○
    / \彡 -
   _|> x`         /
      ( ○       |
    /   |\      /
      /&gt;~~` √
嘣嘣
</pre>
未来IDE愿景
<p>自动完成和snippet:</p>
<ul>
<li>
IDE应该向中文输入法学习</li>
</ul>
<p>
<br />
自然语言理解:</p>
<ul>
<li>
从自然语言生成几乎可用的程序代码</li>
</ul>
<p> </p>
<p>容易学习及使用(对编程语言而言):</p>
<ul>
<li>不仅要容易看到示例代码,还要支持直接将示例代码转变成可用代码<br />
</li>
</ul>
<p> </p>
<p>0知识:</p>
<ul>
<li>不需要学习IDE相关的'jargon'或者快捷键</li>
</ul>
<p> </p>
<p>代码检查:</p>
<ul>
<li>其实也是我对编程语言的期待:分离代码检查语法并完善它(契约还是太弱太不灵活了),最终达到消灭test</li>
</ul>
<p> </p>
<p>消灭UML:</p>
<ul>
<li>灵活强大的程序设计语言应该可以做系统设计,IDE有责任帮助它达成这个目标,而不是引入一门别的语言</li>
</ul>
<p> </p>
<p>自学习:</p>
<ul>
<li>自学习不是观察用户习惯,顺从用户癖好——而是总结出用户可能看不到的新东西。一个有良心的IDE应该说:您的try...catch...是不是太多了?</li>
</ul>
<p> </p>
[元编程系列] nil? respond_to?
都是一些老东西.
<br />
<br /><strong>ICK</strong>是 invocation construction kit 的缩写,里面是什么呢,就是一些 <a target="_blank" href="http://en.wikipedia.org/wiki/Monad_(functional_programming)">Monad</a> 吧。
<br />
<br /><span style="color: cyan;"><a target="_blank" href="http://ick.rubyforge.org/">http://ick.rubyforge.org/</a></span>
<br />
<br />安装:
<br /><pre name="code" class="console">gem install ick</pre>
<br />
<br />一个经常出现的结构:
<br /><pre name="code" class="ruby">@person ? @person.name : nil</pre>
<br />
<br />我们觉得像下面这样写就够了:
<br /><pre name="code" class="ruby">@person.name</pre>
<br />
<br />为了达成上面的目标,我们可能会这样做:
<br /><pre name="code" class="ruby">class NilClass
def method_missing name, *args
nil
end
end</pre>
<br />
<br />不过有些代码倒是希望nil.name会弹出一个异常,所以也有另外一个方法:try()
<br /><pre name="code" class="ruby">class Object
def try method
__send__ method if respond_to? method
end
end</pre>
<br />
<br />结果就是写成
<br /><pre name="code" class="ruby">@person.try :name # 这样也显示了检查@person是否nil的意图
</pre>
<br />但是呢,使用ick,可以做到更强大的链式try哦~~
<br />
<br />先看一段比较烦的代码
<br /><pre name="code" class="ruby">a.b.c.d.e.f if a &amp;&amp; a.b &amp;&amp; a.b.c &amp;&amp; a.b.c.d &amp;&amp; a.b.c.d.e
</pre>
<br />再看一段更令人烦躁的代码
<br /><pre name="code" class="ruby">a.b.c.d.e.f if a.respond_to?(:b) &amp;&amp; a.b.respond_to?(:c) &amp;&amp; a.b.c.respond_to?(:d) &amp;&amp; a.b.c.d.respond_to?(:e) &amp;&amp; a.b.c.d.e.respond_to?(:f)
</pre>
<br />
<br /><strong>我们要把 if 后面那段去掉!</strong>
<br />
<br />为此先对Object添加特性: maybe和try
<br /><pre name="code" class="ruby">require 'ick'
class Maybe &lt; Ick::Guard
guard_with { |value, sym| value }
evaluates_in_calling_environment and returns_result
belongs_to Object
end
class Try &lt; Ick::Guard
guard_with { |value, sym| value.respond_to? sym }
evaluates_in_calling_environment and returns_result
belongs_to Object
end</pre>
<br />
<br />现在我们有舒服的写法了~~~
<br />
<br />下面方法链中,只要其中一个环节产生了nil,就返回nil
<br /><pre name="code" class="ruby">maybe(a){ |x| x.b.c.d.e.f }</pre>
<br />
<br />下面方法链中,只要其中一个环节方法没有定义,就返回nil
<br /><pre name="code" class="ruby">try(a){ |x| x.b.c.d.e.f }</pre>
<br />
<br /><strong>补充</strong>:
<br />
<br />为什么采用这样的结构?直接 try(a).b.c.d.e.f 不是更好么?
<br />
<br />因为:从try(a)起,b,c,d,e,f 都是原对应对象的代理,最后产生的东西和原本期待的 a.b.c.d.e.f 差别很大……
<br />
<br />所以,这段代码放在block里面,就可以把最后返回的值还原成干干净净的对象。
<br />
<br /><strong>2009.4.19 补充:</strong>
<br />
<br />ICK 让我们从另一个方式思考问题——Maybe Monad,但是,ruby 和 python 对象本身已经是 Maybe Monad 了…… 所以还是显得有点不必要。
<br />
<br /><pre name="code" class="ruby">a.b.c.d.e.f rescue nil</pre>
[元编程系列] 邪恶
<p>Ruby 很自由,我们爱死它的自由了,不过对某些邪恶的人来说,这点程度没法满足……<br>
下面的一些代码,出自一个古老的库:evil.rb,你可以 gem install evil-ruby 来获得它。<br><br>
不过原作者可能人间蒸发了,如果想要兼容1.9的 evil-ruby,请用 <a href="http://idm.s9.xrea.com/ratio/2008/07/11/000790.html">Yugui</a>
姐姐的修改版:<br><a target="_blank" href="http://github.com/yugui/evil-ruby/tree/master">http://github.com/yugui/evil-ruby/tree/master</a>
<br><br>
evil.rb 使用了核心库 Ruby/DL 来获得 C 层次的 Ruby 对象访问</p>
<p>不过……Yugui 姐姐你写的 DL,不仅大改 API,而且文档几乎为0…… <img src="/images/smiles/icon_cry.gif" alt=""><br><br>
作为实用主义者,先总结一下 API~ (源文件里注释写得很好,推荐直接看邪恶的源代码)<br><br>
你可以暂停GC的运行:</p>
<pre name="code" class="ruby">require 'evil'
RubyInternal.critical do
# GC暂停了!做坏事要打紧!
end
# critical 块和 RubyInternal 是下面很多方法实现的基础。</pre>
<p>
<br><br>
你还<span style="color: #800080;">可以看看一个对象在内存中是个什么东西</span>
:</p>
<pre name="code" class="ruby">require 'pp'
pp '12'.internal
</pre>
<p>
<br><br>
可以获得地址……:</p>
<pre name="code" class="ruby">'12'.internal_ptr.to_i # 47699480
'12'.internal_ptr.to_i # 47667740,显示这两个'12'是不同的对象
</pre>
<p>
<br><br>
可以获得内部类型在 C 中的定义数值:</p>
<pre name="code" class="ruby">nil.internal_type # 在1.8是32,在1.9是16
</pre>
<p>
<br><br>
还可以解冻对象~~(这个例子是作者举的):</p>
<pre name="code" class="ruby">obj = "Hello World".freeze
obj.frozen? # =&gt; true
obj.unfreeze
obj.frozen? # =&gt; false
</pre>
<p> </p>
<p><strong><span style="color: #0000ff;">解冻是超越安全等级的!</span>
</strong>
<br>
虽然在在高于 0 的安全等级用 unfreeze 时,会装模做样的弹出一个 Error,但是删掉 raise 那行就过去了……<br>
通过 RubyInternal 操作 flag 和 mask,还可以解除 tainted 等状态 -___- </p>
<p>怪不得 Programing Ruby 里面讲安全等级的那章说:</p>
<div class="quote_title">引用</div>
<div class="quote_div">You can also use some devious tricks to do this without using untaint. We’ll leave it up to your darker side to find them.<br>
</div>
<p>教训就是:<strong>千万不要 eval 信不过的代码!</strong></p>
<p><br><br>
检查对象是否直接量(关于直接量和非直接量,请参考 JE 知识库里的 Ruby Hacking Guide):</p>
<pre name="code" class="ruby">12.direct_value? # =&gt; true
</pre>
<p>
<br><br><span style="color: #800080;">可以改变对象所属的类!</span>
</p>
<pre name="code" class="ruby">class A;def 自白;puts '我是一个A';end;end
class B;def 自白;puts '我是一个B';end;end
a = A.new
a.自白 # =&gt; 我是一个A
a.class= B # 无敌的class=
a.自白 # =&gt; 我是一个B
</pre>
<p>
<br><br><span style="color: #800080;">也可以改变继承关系!</span>
</p>
<pre name="code" class="ruby">A.superclass = B
</pre>
<p>
<br><br>
类,就是蜡烛一般弱的东西……噗~~~就没了~~~</p>
<p><img src="/upload/attachment/87399/a44cc8da-329e-382f-883d-388aff79ddf1.jpg" alt=""><br><br>
一心同体……共享实例变量:</p>
<pre name="code" class="ruby">class Body
attr_accessor :heart
end
good_guy = Body.new
good_guy.heart = 'good'
bad_guy = Body.new
bad_guy.share_instance_variables good_guy # 建立连接,同步率直线上升!
puts bad_guy.heart # =&gt; kind
bad_guy.heart = 'bad' # 一个修改,全部改变
puts good_guy.heart # =&gt; bad
</pre>
<p>
<br><br>
复制单例方法:</p>
<pre name="code" class="ruby">a.grab_singleton_methods b
</pre>
<p>
<br><br><span style="color: #800080;">著名的 class to module:</span>
</p>
<pre name="code" class="ruby">class A
include Array.as_module # A可以当Array用了~
end
</pre>
<p>
<br><br>
Ruby不支持多重继承?当然支持了~</p>
<pre name="code" class="ruby">class C
inherit A, B # 后面的同名方法会覆盖前面的
end
</pre>
<p>
<br><br>
KernellessObject——更清洁干净的 BlankSlate 替代物,用来做基于 method_missing 的 DSL 载体非常合适。</p>
<p>在1.9里面返回一个 BasicObject。</p>
<pre name="code" class="ruby">clean_obj = KernellessObject.new # 在irb里会弹出一堆错,因为它连inspect方法都没有,irb想偷窥都不行
</pre>
<p>
<br><br>
UnboundedMethod#bind(obj) 原本要求 obj 属于该方法所在的类,不过 force_bind 超越了这个限制。<br>
下面是作者给的例子,我无耻的copy出来了:</p>
<pre name="code" class="ruby">foo_klass = Class.new do
def greet; "#{self.inspect} says 'Hi!'"; end
end
obj = []
greet = foo_klass.instance_method(:greet)
greet.bind(obj).call # raises TypeError
greet.force_bind(obj).call # =&gt; "[] says 'Hi!'"
</pre>
<p>
<br><br>
还有两个简单的self的运用,其实现和C无关:</p>
<pre name="code" class="ruby">class Object
def meta_class
class &lt;&lt; self
self
end
end
end
# meta_class(或者singleton_class,或者prototype)是一个class,
# 但是对它的修改只影响该对象,不会影响对象的类。
s = '不卫生'
s.meta_class.class_eval do
def xit
'xit'
end
end
s.xit # =&gt; 'xit'
'很卫生'.xit # =&gt; undefined method,String没有被改变
</pre>
<p> </p>
<p> </p>
<pre name="code" class="ruby">class Proc
def self
eval 'self', self
# eval的效果是——获得proc所在的对象,而直接用self只返回Proc本身
 end
end
</pre>
<p> </p>
[准翻译][精心提炼,绝对清纯] Haskell in 5 steps
<p><span style="color: #3366ff;"><strong>1. 准备工作</strong>
</span>
</p>
<p> </p>
<p>官网下载 <a href="http://haskell.org/ghc/download_ghc_6_10_1.html#binaries">GHC</a>
,大约有50M,然后阅读 <a href="http://www.haskell.org/haskellwiki/Haskell_in_5_steps">Haskell in 5 steps</a>
</p>
<p> </p>
<p> </p>
<p><strong><span style="color: #3366ff;">2. 准备之余</span>
</strong>
</p>
<p> </p>
<p>建一个目录,取名为“1”,进入这个目录</p>
<p> </p>
<p>写 hello.hs</p>
<pre name="code" class="haskell">main = print "hello"</pre>
<p> </p>
<p>写 fib.hs</p>
<pre name="code" class="haskell">fib 0 = 0
fib 1 = 1
fib n = fib(n-1) + fib(n-2)</pre>
 
<p> </p>
<p><strong><span style="color: #3366ff;">3. 跑程序</span>
</strong>
</p>
<p> </p>
<p>下载完毕,安装</p>
<p> </p>
<p>编译hello.hs (<span style="color: #ff00ff;">编译示例</span>)</p>
<pre name="code" class="console">&gt; ghc -o hello hello.hs
&gt; hello.exe</pre>
<p> </p>
<p>运行ghci (<span style="color: #ff00ff;">解释与交互示例</span>)</p>
<pre name="code" class="console">&gt; ghci
Prelude &gt; :load fib.hs
*Main &gt; fib 10
89
&gt; :q</pre>
<p> </p>
<p> </p>
<p><strong><span style="color: #3366ff;">4. 再跑一个高深点的程序</span>
</strong>
</p>
<p> </p>
<p>写parallel.hs(<span style="color: #ff00ff;">并行示例</span>,`par`连接——并行运行,`pseq`连接——顺序运行)</p>
<pre name="code" class="haskell">import Control.Parallel
main = a `par` b `pseq` print (a + b)
where
a = fac 10
b = fac 20
fac 0 = 1
fac n = n * fac (n - 1)</pre>
 
<p>编译并运行</p>
<p>    <span style="color: #003366;">-O2</span>:优化等级2,即最牛x的优化,</p>
<p>    <span style="color: #003366;">--make</span>:不用写 make file 的make,</p>
<p>    <span style="color: #003366;">-threaded</span>:多线程支持</p>
<pre name="code" class="console">&gt; ghc -O2 --make para.hs -threaded
&gt; para.exe</pre>
<p> </p>
<p> </p>
<p><strong><span style="color: #3366ff;">5. 总结</span>
</strong></p>
<p> </p>
<p>打开 ghc 的安装目录,转进 doc,打开 index.htm,ctrl+D 收藏(firefox),睡觉。</p>
懒惰的 Hash (以前怎么没发现这个好东西呢?)
<pre name="code" class="ruby">fac = Hash.new {|h, n| n == 0 ? h[n] = 1 : n * h[n - 1]}
p fac[4000]</pre>
<br />
<br />不错~
<br />
<br />不过fac[6000]就报错了……22619 levels
<br />
<br />相比之下,haskell算 fac 50000 都没问题,虽然会狂读硬盘大卡一阵……
<br />
<br />
<br />最后给个改进版:
<br />
<br /><pre name="code" class="ruby">
fac = Hash.new {|h, n|h[n] = n * h[n - 1]}
fac[0] = 1
100.times {|i|fac[i*500]} # 还是能算的嘛
fac[50000] # =&gt; failed to allocate memory -___-
</pre>
<br />
<br />另外给个题外的trick:
<br />
<br /><pre name="code" class="ruby">
a, *b = [1, 2, 3]
a # =&gt; 1
b # =&gt; [2, 3]
</pre>
tuple和list基础
读 <a target="_blank" href="http://darcs.haskell.org/yaht/yaht.pdf">yaht</a> 小记
<br />
<br />跳过洋洋洒洒的理念部分……直接进入控制台……
<br />
<br /><pre name="code" class="Prelude">
--comments
{-
block comments
-}
; --line breaks
--tuple, 固定长
(1, 2, 3, 4) --二人成 pair,三人成 triple,四人成 quadruple (谢谢R9X~)
fst(1, 2) --取出第一个元素
snd(3, 4) --取出第二个元素
--list,任意长,每个元素的类型必须相同
[1, 2, 3] --1 : 2 : 3 : []的语法糖
0 : [1, 2] --colon is a 'cons' operator
let l = [1, 2, 10] --ghci 用 let 定义,.hs文件里就不用
length l
head l
tail l
--string 就是内容为 char 的 list 的语法糖
"f" ++ "uck" --concat 操作,注:不会自动将 char 转为 string
show (5 ^ 5) --ruby.to_s,java.toString
read "66" --ruby.to_i
--常用 list 操作
map Char.toUpper "xiao case"
filter Char.isLower "UlPoPwEeRr"
--"lower"
let cubic_sum l = foldl (\y x -&gt; y + x ^ 3) 0 l
--立方和
--ruby.inject,google.reduce
let max l = foldl (\y x -&gt; if x &gt; y then x else y) 0 l
--最大值
foldr (-) 0 [1, 2, 3, 4]
--1-(2-(3-(4-0))),即 1-2+3-4
--foldr 可以对无限集操作,foldl不行
--foldl 速度快一点
let inf_l = 1 : inf_l --全为 1 的无限表
foldr (:) [] inf_l --等于inf_l
take 10 inf_l --取出前 10 个元素
inf_l !! 10 --取出"第" 10 个元素
</pre>
<br />
<br />补充:除了 yaht 和 wikibook,外,还可以看看 learn you a haskell for great good。
符号 in Haskell
<p>Haskell把很多数学符号化成了“颜文字”<br />
    (Emacs 好强,还能符号重现)<br />
<br />
\ 即是 λ<br />
<br />
-&gt; 即是 →<br />
<br />
函数名可以用' 结尾<br />
    (关于这个' 的读法,有人读“撇”,中学老师读“派”,长大了才知道读“prime”)<br />
<br />
| 即是大花括号</p>
<p> </p>
<p>&lt;- 就是 ∈</p>
<p> </p>
<p> </p>
<p>
btw,用了两天 ghci……牛头不搭马嘴的出错信息,诸多诡异的限制,连换行都不支持……我要大声疾呼:</p>
<p>你们这帮做 ghci 的,赶快把格拉斯高(Glasgow)升级成兰斯洛特(Lancelot)吧!</p>
<p> </p>
<p> </p>
<p><img height="244" src="/upload/attachment/88415/b1c5a89d-ad04-3ae7-9559-c3b16159ee02.jpg" width="189" alt="" />
  <span style="color: #ff0000;"><strong>---&gt;</strong>
</span>
<img height="243" src="/upload/attachment/88417/136919a1-04b3-3531-89d0-509686eee57d.jpg" width="195" alt="" />
  <span style="color: #ff0000;"><strong>please!</strong>
</span>
</p>
<p> </p>
<p> </p>
<p>-__-b 太虚了还用图片充内容……</p>
CPS
终于看完 yaht 第 4 章了,才知道原来类型系统都能玩这么多花样,而且末节 CPS 更体现了函数式编程的精髓。下面一些例子都是源于书中。
<br />
<br />CPS 是 Continuation Pass Style 的缩写。而 Continuation 和递归有点关系。
<br />
<br />函数的每次 call,都会把调用者的状态压一次栈。直到结尾处,才自己调用自己的函数是尾递归。
<br />
<br />一般递归可以 ... 变成只调用自己一次的递归,然后 ... 就变成了尾递归。
<br /><span style="color: grey;">——慢着,这马赛克是什么回事?</span>
<br />——因为地方太少写不下,只好用点点代替省掉的 n 行 ╮(╯﹏╰)╭ <span style="color: grey;">(群众纷纷扔番茄)</span>
<br />——OK、OK……其实我是这么想的:某天总会有人搜到这篇文章,看见 <span style="color: darkred;"><strong>3 个点</strong></span>,以为是搜索引擎省略的,打开来,才发现这确实是 <span style="color: darkred;"><strong>3 个点</strong></span>……<span style="color: grey;">(群众放下番茄,开始扔砖头)</span>
<br />
<br /><span style="color: grey;">尾递归有什么好处呢?</span>
<br />
<br />设 f1, f2 都是 f 的“实例”,f1 在尾部 调用 f2。这里用“shi力”指代它的局部变量和参数蹲在调用栈中、所占用的那个坑。
<br />f1 调 f2 的时候,f1 要拉的都拉完了,所以我们可以将占坑不拉的 f1 赶出来,让 f2 宽衣入坑——满塞!一个坑解决所有问题!此谓之“尾递归优化”。
<br />如此下去,就算递归个几亿重,也不会"坑溢出"(stack overflow)。
<br />
<br />可惜的是,由于 ... 的原因,大部分非函数式语言的编译器、运行时不支持尾递归优化,还有实现了又删掉的……<span style="color: grey;">(群众继续扔砖头)</span>
<br />
<br />幸好我们还有更彻底的方法:把 f1 改头换面,当成 f2 。这种代工拉 shi,把 f1 数据当成 f2 数据的方式 <a target="_blank" href="http://en.wikipedia.org/wiki/Continuation#History">启发了某些大牛</a> ,终于提出了 Continuation 这个东西。
<br />
<br />Continuation 看起来像个循环或者递归,但只有1个“shi力”,而且每次调用只走一步。
<br />中文名?个人以为借用柏格森的 <a target="_blank" href="http://en.wikipedia.org/wiki/Continental_philosophy">绵延</a> 就很好,也体现了单shi力“如滔滔江水,绵延不绝”的强大……
<br />
<br />于是大部分语言都有了自己的“绵延”,以显示生命和灵性所在(柏格森你是个大忽悠……)。这个貌似有状态的东西,数学上应该不能是个函数吧?
<br />嗯,有个温馨的东西(Monad)就是干这个的,但是还有 CPS 可以做这种工作 —— 它是 Style 而非 Type —— 的确是普普通通,来来去去的那道菜 —— 函数。
<br />
<br />看看书上的 CPS fold:
<br /><pre name="code" class="haskell">
cfold' f z [] = z
cfold' f z (x:xs) = f x z (\y -&gt; cfold' f y xs)
</pre>
<br />
<br />我觉得“尾行函数”更加符合道学(<a target="_blank" href="http://www.powerset.com/explore/semhtml/Taoist_sexual_practices">Taoist (x:xs) practices</a>),那一撇毛更是可有可无,就改成了:
<br /><pre name="code" class="haskell">
cfold ::
[x] -&gt;
acc -&gt; -- accumulator type
(x -&gt; acc -&gt; (acc -&gt; acc) -&gt; acc) -&gt; -- 尾行函数 type
acc
cfold [] acc f = acc
--最后两个 acc 可以用 t 或者什么符号代替,但是想个新名字又何苦呢
cfold (x:xs) acc f = f x acc (\acc -&gt; cfold xs acc f)
</pre>
<br />
<br />练习1. 请一口气读完:参数叁是参数叁是函数的叁参数函数的叁参数函数。
<br />
<br />这种“<a target="_blank" href="http://thottbot.com/?q=1382">超适应齿轮</a>”,可以让我们组装各种新函数,如foldl:
<br /><pre name="code" class="haskell">
nfoldl :: [x] -&gt; acc -&gt; (x -&gt; acc -&gt; acc) -&gt; acc
nfoldl list acc f = cfold list acc (\x acc g -&gt; f x (g acc))
</pre>
<br />
<br />试试nfoldl:
<br /><pre name="code" class="haskell">
nfoldl [1,2,3] [] (:)
-- -&gt; [1,2,3]
</pre>
<br />
<br />但直接用才体现了那个……给它指定如何去连接循环它才会循环……
<br /><pre name="code" class="haskell">
cfold [1..10] [] (\x acc cfold -&gt; cfold (x : acc))
-- -&gt; [10,9,8,7,6,5,4,3,2,1],先构造表再调用
cfold [1..10] [] (\x acc cfold -&gt; x : (cfold acc))
-- -&gt; [1,2,3,4,5,6,7,8,9,10],先调用再构造表
</pre>
<br />
<br />2009.4.6 补充:
<br />tangtong 问我为什么体现了“精髓”,我觉得是避免了Monad,使代码看起来更 FP 吧……
<br />
<br />最后找个台阶:初学Haskell,很多东西也是一知半解……这个东西还是蛮抽象的
<br />补充: 之所以把 f 放到最后,是因为ruby的习惯,于是这个东西也能很容易的写成ruby
11个8问题
昨天看到一个问题:
<br />用+-*/及括号组装11个8,最后等于2007
<br />
<br /><a target="_blank" href="http://libudi.iteye.com/blog/356905">传送门</a>
<br />
<br />试着用 Haskell 做一下:solve.hs(对不起这个只是检验有没有解而不是给出解……)
<br /><pre name="code" class="haskell">
module Main where
--先定义两个用的东西
contains [] elem = False
contains (x:xs) elem =
if x == elem
then True
else contains xs elem
merge l [] = l
merge l (x:xs) =
if contains l x
then merge l xs
else merge (x:l) xs
ops = [(+),(-),(*),(/)]
--用list comprehension是简单,但过程就米了……
mergeLists n = \m acc -&gt;
merge acc [ op x y | op &lt;- ops, x &lt;- res (n-m), y &lt;- res m ]
res 1 = [8]
res n = foldr (mergeLists n) [] [1..(n-1)]
--有解就True,没解就False
main = print (contains (res 11) 2007)
</pre>
<br />
<br />编译运行(很费cpu和时间,幸好是双核机器……)
<br /><pre name="code" class="console">
ghc -O2 --make solve.hs -o whether_there_is_a_solution
</pre>
<br />
<br />结果估计要算几年……
<br />
<br />补充:谢谢R9X mm。最后 mark 一下 Prelude 的 ref..
<br /><a target="_blank" href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html">http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html</a>
<br />
<br />题外,Haskell真的很舒畅,往往不用想什么内存吃多少的问题。
<br />得益于lazy和编译优化,定义了这么大一个List,运行时候才占4M内存,ruby如果用这种糟糕算法早就爆了/(ㄒoㄒ)/~~
<br />
<br /><span style="color: red;"><strong>4月12日修改:</strong></span>
<br />现在有过程了~ 能算 8 个 8(数秒), 但是更多的就会满内存了。
<br />
<br />输出是前缀表达式。
<br /><pre name="code" class="haskell">
module Main where
elem' y [] = False
elem' y@(n, _) (x:xs) =
if n == fst x
then True
else elem' y xs
merge l [] = l
merge l (x:xs) =
if elem' x l
then merge l xs
else merge (x:l) xs
merge' len l1 l2 =
if len &lt; 5
then merge l1 l2
else l1 ++ l2
ops = [
(\ (x, xx) (y, yy) -&gt; if y /= 0 then (x / y, ('/':xx) ++ yy) else (0, "div by 0")),
(\ (x, xx) (y, yy) -&gt; (x + y, ('+':xx) ++ yy)),
(\ (x, xx) (y, yy) -&gt; (x - y, ('-':xx) ++ yy)),
(\ (x, xx) (y, yy) -&gt; (x * y, ('*':xx) ++ yy))
]
mergeLists n = \m acc -&gt;
merge' n acc
[ op x y |
op &lt;- ops, i &lt;- [0..3], x &lt;- res (n - m), y &lt;- res m ]
res 1 = [(8, "8")]
res n = foldr (mergeLists n) [] [1..n-1]
findelem n [] = "No result"
findelem n (x:xs) =
if n == fst x
then snd x
else findelem n xs
main = do
putStrLn "How many 8:"
l1 &lt;- getLine
let n = read l1
putStrLn "The result you want:"
l2 &lt;- getLine
let m = read l2
putStrLn (findelem m (res n))
</pre>
<br />
<br /><img src="/upload/attachment/93566/8aa8e9f7-66d6-3b65-8307-12dd846d99e1.jpg" />
<br />
.NET 4.1 猫类 和 QCL 纠缠
<img src="/upload/attachment/90146/0fcfbe2f-2484-3cae-9b8f-f4c0c112af34.jpg" />
<br />
<br />今天看到的:
<br /><a target="_blank" href="http://www.cnblogs.com/blodfox777/archive/2009/04/02/1427972.html">http://www.cnblogs.com/blodfox777/archive/2009/04/02/1427972.html</a>
<br />
<br />愚人节“新”闻在这:
<br /><a target="_blank" href="http://www.hanselman.com/blog/NET41PreviewNewBaseClassLibraryBCLExtensionMethodsRFC.aspx">http://www.hanselman.com/blog/NET41PreviewNewBaseClassLibraryBCLExtensionMethodsRFC.aspx</a>
<br />
<br />不过,QCL 里面早就能模拟这个了~
<br />
<br /><strong>简单基础</strong>:
<br />
<br /><a target="_blank" href="http://www.ibm.com/developerworks/cn/linux/other/quant/index.html">http://www.ibm.com/developerworks/cn/linux/other/quant/index.html</a>
<br />
<br />量子计算机的寄存器(量子比特)基态可以为 |0&gt; 或 |1&gt;。
<br />
<br />每个寄存器状态是基态的叠加。如量子态:
<br />(1/sqrt(2)) |0&gt; + (1/sqrt(2)) |1&gt;
<br />
<br />这个量子态中,两个基态的系数都可以为复数,系数的模的平方的和等于 1。
<br />
<br />测量会使得量子态坍缩,变成基态之一。上面的量子态测量后,会变成 |0&gt; 或者 |1&gt;。
<br />再次测量 |0&gt;,仍然是 |0&gt;;再次测量 |1&gt;,仍然是 |1&gt;。
<br />
<br />可以认为:基态的系数的模的平方 == 测量得到该基态的几率。
<br />
<br />频谱:基态的几率叠加。如上面的量子态,频谱为:
<br />0.5 |0&gt; + 0.5 |1&gt;
<br />
<br /><strong>用带两个寄存器的量子计算机模拟</strong>:
<br />
<br />假设 a 为放射性原子,1小时内衰变的几率为 50%。用 |.0&gt; 代表衰变,|.1&gt; 代表没衰变。
<br />在 QCL 中,可以用 Hadamard 算符 (Mix) 制备这种状态:
<br /><pre name="code" class="qcl">qureg a[1];
Mix(a);</pre>
<br />
<br />现在 a = 0.707|.0&gt; + 0.707|.1&gt;
<br />
<br />假设 b 为猫,|0.&gt; 代表死,|1.&gt; 代表活。制备纠缠态
<br /><pre name="code" class="qcl">qureg b[1];
CNot(b,a);</pre>
<br />
<br />CNot(b,a)含义为“not b if a”。于是,如果 a 没衰变,即|.1&gt;,那么 b 为not |0.&gt;,即|1.&gt;,也就是活。
<br />
<br />现在猫的状态可以看做 b = 0.707|0.&gt; + 0.707|1.&gt;,半死不活。(确切的说不是这个,而是一个纠缠态)
<br />测量 a 将确定它的生死(&gt;^ω^&lt;)喵:
<br /><pre name="code" class="qcl">measure(a);</pre>
<br />
<br />
<br />村长对于此事故的评价:
<br /><span style="color: #666666;">这件事,我会派名侦探去调查了的喵
<br />这是下一封委托信喵
<br />当然做新武器也是必要的喵
<br />最近老觉得音响不够震撼喵
<br />要是有什么加强一下就好了喵
<br />真的很期待喵
<br /></span>
<br />
<br />ps:Ruby也可以玩随机类:
<br /><pre name="code" class="ruby">
a = [String, Array, Hash][rand(3)].new
</pre>
GC、shared_ptr 和 arena 是很强,不过……
大部分情况只是需要一个变长度的内存,用一下就丢了。
<br />所以用下面这个东西就可以了,而且速度更快…… 缺点是只增不减-__-。
<br />
<br />代码要重用,内存也要重用……
<br />
<br /><pre name="code" class="C++">
#pragma once
#include "utils.h"
#include &lt;cstdlib&gt;
//NOTE: this class should be used only on POD or C struct
//any class with a constructor / destroyer should NEVER invoke alloc
template&lt;class T&gt;
class temporal {
private:
void* buf;
unsigned long cap;
temporal(const temporal&amp;);
void operator=(const temporal&amp;);
public:
temporal() : buf(0), cap(0) {}
~temporal() { free(buf); }
inline T* alloc(unsigned long sz) {
if(sz &gt; cap) {
free(buf);
buf = malloc(sz*sizeof(T));
cap = sz;
}
return (T*)buf;
}
};
</pre>
IO 等两则
<strong><span style="color: blue;">1.IO</span></strong>
<br />
<br />Haskell 的函数,是数学定义的函数。
<br />
<br />IO 的行为有异于函数: f(a) != f(b)。
<br />
<br />main 必须返回 IO 类型。ghc 使用 IO 的常用形式:
<br /><pre name="code" class="haskell">module Main where
import IO
main = do
hSetBuffering stdin LineBuffering
--...</pre>
<br />
<br />和指令式语言不同,Haskell的 return x 将 x 变成 Monad(而 IO Monad class 将 return x 定义为了 IO x)
<br /><pre name="code" class="haskell">Prelude&gt; :t (return ())
(return ()) :: (Monad m) =&gt; m ()</pre>
<br />
<br />而 &lt;- 操作在 IO x 中提取出值 x 赋给左边
<br /><pre name="code" class="haskell">answer &lt;- getLine</pre>
<br />
<br />API小结:(Handle……果然是哪个词不直观就用哪个么……)
<br /><pre name="code" class="haskell">--File, FilePath 即是 String
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
openFile :: FilePath -&gt; IOMode -&gt; IO Handle
readFile :: FilePath -&gt; IO String
writeFile :: FilePath -&gt; String -&gt; IO ()hClose :: Handle -&gt; IO ()
hClose :: Handle -&gt; IO ()
hIsEOF :: Handle -&gt; IO Bool
--Handle相关的函数
hGetChar :: Handle -&gt; IO Char
hGetLine :: Handle -&gt; IO String
hGetContents :: Handle -&gt; IO String
hPutChar :: Handle -&gt; Char -&gt; IO ()
hPutStr :: Handle -&gt; String -&gt; IO ()
hPutStrLn :: Handle -&gt; String -&gt; IO ()getChar :: IO Char
--无需Handle版本
getLine :: IO String
getContents :: IO String
putChar :: Char -&gt; IO ()
putStr :: String -&gt; IO ()
putStrLn :: String -&gt; IO ()
--用途见下面
bracket :: IO a -&gt; (a -&gt; IO b) -&gt; (a -&gt; IO c) -&gt; IO c</pre>
<br />
<br />bracket 是一个提升安全性的套套,它隐藏了一些异常处理的细节,并保证关闭文件等处理的执行。
<br /><pre name="code" class="haskell">getOneLineFrom1 = bracket
(openFile "1.txt" ReadMode)
hClose
hGetLine
</pre>
<br />
<br />上次看见有人说 Haskell 处理大量 IO 的东西会累死…… 乌索普! 看这 bracket 比 java 简单多少!
<br />
<br /><span style="color: blue;"><strong>2.一些细节备忘</strong></span>
<br />
<br />行首缩进用空格,不要用tab (得让编辑器把tab高亮出来才行),如果用tab,则要保证空格的缩进=8字符以和tab统一。
<br />
<br />main中,do 连起来的几行,如果不是 IO 语句结尾,就应该用 return () 产生一个空 IO ()
<br />
<br />case 的使用法
<br /><pre name="code" class="haskell">fun x = case x of 0 -&gt; "zero"; 1 -&gt; "one"; _ -&gt; "many"
--_ 也可以用 otherwise 代替</pre>
<br />
<br />Haskell 会把缩略的类型展开,譬如
<br />type InfType = Int -&gt; InfType
<br />就会导致 "infinite type"错误。
Win32 not paintful any more
Haskell有一个库 —— Win32
<br />
<br /><span style="color: gray;">更新:换用 ghc 6.10.2 后,Win32 的表现还不错~
<br />4 月 1 日的版本修正了大量的 bug </span>
<br />
<br /><pre name="code" class="haskell">module Main where
import System.Win32.DLL (getModuleHandle)
import Graphics.Win32
import Graphics.Win32.Message
import Graphics.Win32.Window
import Data.Int
import Data.Maybe
import Control.Monad
import Foreign.C.String
import Foreign.C.Types
foreign import stdcall "PostQuitMessage" postQuitMessage
:: Int32 -&gt; IO ()
main = do
let clsName = mkClassName "My Window Class"
hinst &lt;- getModuleHandle Nothing
whiteBrush &lt;- getStockBrush wHITE_BRUSH
curArrow &lt;- loadCursor Nothing iDC_ARROW
mAtom &lt;- registerClass (
cS_DBLCLKS,
hinst, -- HINSTANCE
Nothing, -- Maybe HICON
Just curArrow, -- Maybe HCURSOR
Just whiteBrush,-- Maybe HBRUSH
Nothing, -- Maybe LPCTSTR
clsName)
--faint so many Nothing...
when (isJust mAtom) $ do
hwnd &lt;- createWindow
clsName
"test window"
(wS_THICKFRAME + wS_CAPTION + wS_SYSMENU)
Nothing  
Nothing
Nothing
Nothing
Nothing
Nothing
hinst
wndProc
showWindow hwnd sW_SHOWNORMAL
updateWindow hwnd
allocaMessage pump
unregisterClass clsName hinst
pump lpmsg = do
fContinue &lt;- getMessage lpmsg Nothing
when fContinue $ do
translateMessage lpmsg
dispatchMessage lpmsg
pump lpmsg
render :: HWND -&gt; HDC -&gt; IO ()
render hwnd hdc = do
setBkMode hdc tRANSPARENT
setTextColor hdc $ rgb 0 0 0
textOut hdc 5 5 "hello world!"
wndProc :: HWND -&gt;
WindowMessage -&gt;
WPARAM -&gt;
LPARAM -&gt; IO LRESULT
wndProc hwnd wm wp lp
| wm == wM_DESTROY = do
postQuitMessage 0
return 0
| wm == wM_PAINT = onPaint
| otherwise = defWindowProc (Just hwnd) wm wp lp
where
onPaint = allocaPAINTSTRUCT $ \ lpps -&gt; do
hdc &lt;- beginPaint hwnd lpps
render hwnd hdc
endPaint hwnd lpps
return 0
</pre>
<br />
<br />解释:
<br />ghci -fglasgow-exts -luser32 gui_hello.hs
<br />
<br />编译:
<br />ghc -optl-mwindows -fglasgow-exts --make gui_hello.hs
<br />
<br />ps:
<br />e-text editor 的 haskell bundle 挺不错
<br />
<br />4 月 10 日补充:
<br />现在决定将我的编辑器迁移到 haskell 了~
CPS之2
<a target="_blank" href="http://night-stalker.iteye.com/blog/356708">上一篇</a>总结了一下CPS,感觉还是不够理解,于是继续看wiki book,加深一下体会。
<br />
<br />先定义一些缩略语:
<br />CPS: continuation passing style
<br />TR:&nbsp; tail recursion
<br />TC:&nbsp; tail call
<br />TCO: tail call optimization
<br />
<br />先看一个普通的递归是如何变成 TR 的。
<br />
<br />例如一个求和函数:
<br /><pre name="code" class="haskell">sum [] = 0
sum (x:xs) = x + (sum xs)</pre>
<br />
<br />它并不是 TR,因为它的最后一步是 + 。
<br />为了变成 TR,我们可以增加一个自变量来保存结果:
<br /><pre name="code" class="haskell">sum' res [] = res
sum' res (x:xs) = sum' (res+x) xs
sum list = sum' 0 list</pre>
<br />
<br />很不错吧?这样就能保证让编译器进行 TCO 了。
<br />这个trick 被滥用和推广以后——可以增加自变量,当然也能增加函数——就变成了 CPS。
<br />
<br />so we get:
<br /><div class="quote_title">Ricky Martin &lt;Livin' La Vida Loca&gt; 写道</div><div class="quote_div">Upside (down) Inside Out</div>
<br /><span style="color: gray;">这首歌真的很 hot,演唱会上面那个 mm 也很 hot……</span>
<br />
<br />练手:先将一个简简单单的函数改成 CPS。
<br /><pre name="code" class="haskell">-- origin
f x = ((x + 1) * 2 - 3) * 4
-- cps
f1 x cc = cc (x + 1)
f2 x cc = cc (x * 2)
f3 x cc = cc (x - 3)
f4 x cc = cc (x + 4)
f' x cc = f1 x (\x cc -&gt; f2 x (\x cc -&gt; f3 x (\x cc -&gt; f4 x cc)))
f'cps x = f' x (\x -&gt; x)</pre>
<br />
<br />感觉良好…… haskell 有专门语法杀括号:(其实还是很难看)
<br /><pre name="code" class="haskell">
f''cps x = f1 x $
\x -&gt; f2 x $
\x -&gt; f3 x $
\x -&gt; f4 x $
print</pre>
<br />
<br />最后一步传一个print,便是打印结果,so sweet~
<br />
<br />非常有趣:这个语法糖差不多就是后缀表达式了……
Lucas-Lehmer 法寻找 Messen 数
这个方法是最快的,比 Rabin-Miller test更快。
<br />原理参见 <a target="_blank" href="http://zh.wikipedia.org/w/index.php?title=%E5%8D%A2%E5%8D%A1%E6%96%AF-%E8%8E%B1%E9%BB%98%E6%A3%80%E9%AA%8C%E6%B3%95&amp;variant=zh-cn">wiki</a>
<br />
<br />数学公式几乎不用改,就能用 Haskell 写出来。(顺便晒一晒编辑器……)
<br />
<br /><img src="/upload/attachment/91960/2fbaa86a-2d32-33c6-a047-c4f987bb388b.png" />
<br />
<br />补充:写了个 2 线程的版本(如附件),编译时需要加 -O3 和 -threaded,运行时需要添加参数 +RTS -N2 (3个本地线程就是-N3)。
用 haskell 扩展 ruby
Haskell 是“纯洁的”函数式语言,可以解释运行,也可以编译成本地代码。
<br />其编译过程大致是先生成 C 代码(确切的说是 C--),然后使用自带的 gcc 编译。
<br />Haskell 编译后体积小,性能好,不需要笨重的运行时,在
<br /> <a target="_blank" href="http://shootout.alioth.debian.org/">http://shootout.alioth.debian.org/</a>
<br />的 benchmark 排名经常超过 java 和 D。
<br />
<br />与它相似的函数式语言的简单比较如下:
<br />
<br /><img src="/upload/attachment/92656/0031f875-faae-3884-927d-403cddbf3172.png" />
<br /><span style="color: gray;">注意:Erlang, Scheme 都是不纯洁的哦。
<br /></span>
<br />pure 和 lazy(惰性求值)密切相关。
<br />由于纯函数(就是我们中学课本上的函数,而不是一般编程语言说的“函数”)表现稳定,所以求值后可以存起结果。如果下次调用参数相同,可以直接返回这个结果(似乎编译器的优化要更复杂一些?)。于是纯函数式的语言用惰性求值不会产生任何性能问题。
<br />
<br />惰性求值有个好处是可以随心所欲定义无限长的列表,你用到其中某一项时它才会算出那项的值。
<br />eager 的就不行——定义时就会对这个 list 求值,无限循环了。
<br />
<br />---------------------------------------------------------------------------------
<br />
<br />Haskell vs Ruby:
<br />彻底的函数式 vs 彻底的面向对象,静态类型 vs 动态类型,极度纯洁 vs 极度不纯洁,面向数学公式 vs 面向自然语言,缩进 vs end ……
<br />
<br />一方的弱项正好是另一方的长处,所以用 Haskell 扩展 Ruby 还是很有意义的。
<br /><span style="color: gray;">当然两者也有一些共同的缺点,譬如:代码量都比较短。</span>
<br />
<br />首先请看一个简单的用 Haskell 产生dll的示例:
<br /><a target="_blank" href="http://www.haskell.org/ghc/docs/latest/html/users_guide/win32-dlls.html">http://www.haskell.org/ghc/docs/latest/html/users_guide/win32-dlls.html</a>
<br />
<br />不过 dllMain.c 和各种编译参数太古板了,可以写一个脚本省掉这个过程:
<br />
<br /><strong>makedll.rb</strong> 将当前目录下所有.hs文件都检查一遍,生成dllMain.c,然后自动编译链接产生dll。<strong><span style="color: indigo;">并且连带产生 interface.rb。</span></strong>
<br /><pre name="code" class="ruby">
### Begin Config
### Set output dll name
#outputdll = 'some name.dll'
### Set ghc options
#options = '-O2 -threaded'
### Set heap and stack options
#heap_and_stack = '-H128m -K1m'
### End Config
if ARGV[0] == 'clean'
system 'del *.o *.hi *.c *.a *.h'
exit
end
# tidy config options
outputdll ||= "#{File.basename File.expand_path('.')}.dll"
options ||= ''
heap_and_stack &amp;&amp;= "char *ghc_rts_opts = \"#{heap_and_stack}\";"
# hash for haskell-to-C type cast. needs to be complete in the future
TypeCast = { 'Int' =&gt; 'long',
'Char' =&gt; 'char',
'String' =&gt; 'char*'
}
# cast signature from haskell to ruby/dl style
def signature_cast line
if line =~ /^\s*foreign\s+export\s+stdcall\s+(\w+)\s+\:\:\s+(.+?)\s+\-\&gt;\s+IO\s+(\w+)\s*$/
func = $1.dup
ret_type = TypeCast[$3.strip]
plist = $2.split('-&gt;').map{|e| TypeCast[e.strip] }.join(',')
"extern \"#{ret_type} #{func}(#{plist})\", :stdcall"
end
end
# scan files
fnames = Dir.entries('.').select do |f|
!(File.directory? f) &amp;&amp; f =~ /\.hs$/
end
modules = []
fnames_with_ext = [] # files containing extern functions
rb_interface = [] # ruby interface modules
fnames.each do |fn|
File.open fn do |f|
# search for module xxx
module_name = nil
while line = f.gets
if line =~ /^\s*module (\w+)/
module_name = $1
break
end
end
# search for extern function signatures
externs = []
while line = f.gets
sig = signature_cast line
externs &lt;&lt; sig if sig
end
if externs != []
modules &lt;&lt; module_name
fnames_with_ext &lt;&lt; fn
rb_interface &lt;&lt; externs.join("\n")
end
end
end
# build ruby interface
File.open 'interface.rb', 'w' do |f|
ruby_template = &lt;&lt;-ES
require 'dl/import'
require 'dl/types'
module %s
extend DL::Importer
dlload '%s'
%s
end
ES
outputdll =~ /^([a-zA-Z]+)/
module_name = $1
module_name[0] = module_name[0].chr.upcase
f.puts ruby_template % [module_name, outputdll, rb_interface.join("\n ")]
end
# build dllMain.c
require 'erb'
File.open 'dllMain.c', 'w' do |f|
f.puts ERB.new(DATA.read).result(binding)
end
# compile
fnames_with_ext.each do |fn|
system "ghc -c \"#{fn}\" -fglasgow-exts"
end
system "ghc -c dllMain.c"
# link
objs = fnames_with_ext.map do |fn|
"\"#{fn.sub /hs$/,'o'}\" \"#{fn.sub /\.hs$/,'_stub.o'}\""
end.join ' '
system "ghc -shared dllMain.o #{objs} -o \"#{outputdll}\" #{options}"
__END__
#include &lt;windows.h&gt;
#include &lt;Rts.h&gt;
&lt;%= heap_and_stack %&gt;
&lt;% modules.each do |m| %&gt;
extern void __stginit_&lt;%= m %&gt;(void);
&lt;% end %&gt;
static char* args[] = { "ghcDll", NULL };
BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, void* reserved)
{
if (reason == DLL_PROCESS_ATTACH) {
&lt;% modules.each do |m| %&gt;
startupHaskell(1, args, __stginit_&lt;%= m %&gt;);
&lt;% end %&gt;
return TRUE;
}
return TRUE;
}
</pre>
<br />
<br />------------------------------------------------------------------------------
<br />
<br />简单过程示例:
<br />
<br />保证 ghc 6.10.2 (最流行的haskell编译器和解释器) 和 ruby 1.9 (内置DL库)。
<br />
<br />建一个文件夹adder,在里面新建 adder.hs,内容如下
<br /><pre name="code" class="haskell">
module Adder where
adder :: Int -&gt; Int -&gt; IO Int –– gratuitous use of IO
adder x y = return (x+y)
foreign export stdcall adder :: Int -&gt; Int -&gt; IO Int
</pre>
<br />
<br />把上面的 makedll.rb 扔进去,产生 adder.dll 和 interface.rb:
<br /><pre name="code" class="console">
ruby makedll.rb
ruby makedll.rb clean
</pre>
<br />
<br />用 ruby/DL 调用这个 dll 非常简单:
<br /><pre name="code" class="ruby">
require 'interface.rb'
puts "5+8=#{Adder.adder(5,8)}"
</pre>
<br />
<br />ruby/DL 调用扩展的好处是可以避免 "dll hell",我的ruby是VC2008编译的,调用gcc产生的动态链接库也不会出现 segfault。
<br />
<br />补充1:推荐使用 ghc 6.10.2 , ghc 6.10.1 可能有问题。
<br />补充2:在linux下编译 haskell 共享库要简单一些,不需要dllMain.c。具体可以参看
<br /><a target="_blank" href="http://blog.haskell.cz/pivnik/building-a-shared-library-in-haskell/">http://blog.haskell.cz/pivnik/building-a-shared-library-in-haskell/</a>
<br />补充3:修改 makedll.rb,可以产生 ruby interface 了。
<br />补充4:2009.9 看到 hubris: (只能在 linux 和 mac 下面用,类似于 rubyinline)
<br /><a target="_blank" href="http://www.infoq.com/news/2009/08/haskell-ruby-hubris">http://www.infoq.com/news/2009/08/haskell-ruby-hubris</a>
<br /><a target="_blank" href="http://github.com/mwotton/Hubris/tree/master">http://github.com/mwotton/Hubris/tree/master</a>
强大的 fold
fold 是重要的操作符(ruby 里面叫 inject)
<br />
<br />基本定义(Prelude.foldr):
<br /><pre name="code" class="haskell">
-- 从右往左卷
foldl f z [] = z
foldl f z (x : xs) = foldl f (f z x) xs
-- 从左往右卷
foldr f z [] = z
foldr f z (x : xs) = f x (foldr f z xs)</pre>
<br />
<br />另一种定义方式是通过 CPS 。
<br />
<br />令 z = 第一个元素,就得到变种 foldl1, foldr1。
<br />
<br />注意 foldl 虽然是尾递归,但是消耗内存和 foldr 一样:
<br />延迟求值使 f z x 不会马上被计算出来,依然会产生很大的调用栈。
<br />
<br />省内存(strict 版本, Data.List.foldl')的定义如下:
<br /><pre name="code" class="haskell">
foldl' f z [] = z
foldl' f z (x:xs) = let z' = f z x in z' `seq` foldl' f z' xs
</pre>
<br />
<br />--------------------------------------------------------------------------
<br /><strong><span style="color: #0033FF;">很多常用的函数都可以通过 fold 产生:</span></strong>
<br /><pre name="code" class="haskell">
sum = foldl (+) 0
product = foldl (*) 1
and = foldl1 (&amp;&amp;)
or = foldl1 (||)
(++) ys = foldr (:) ys
length = foldl (\n x -&gt; 1 + n) 0
reverse = foldl (\ys x -&gt; x : ys) []
map f = foldr (\x ys -&gt; f x : ys) []
filter p = foldr (\x ys -&gt; if p x then x : ys else ys) []
</pre>
<br />
<br />下面,let fold = foldr,看看还能玩什么花样。
<br />
<br />---------------------------------------------------------------------------
<br /><strong><span style="color: #0033FF;">“融”定理(the fusion property of fold)</span></strong>
<br />如果 <em>h</em> (<em>g</em> x z) = <em>f</em> x (<em>h</em> z)
<br />那么 <em>h</em> . <em>fold</em> <em>g</em> z = <em>fold</em> <em>f</em> (<em>h</em> z)
<br />
<br />应用举例:
<br />(* 3) . sum = (* 3) . fold (+) 0
<br />所以这里 h = (* 3), g = (+)
<br />
<br />令 f x y = x * 3 + y,则有
<br />h (g x z) = f x (g z)
<br />
<br />再根据上面的定理
<br />(* 3) . sum = fold f (h 0) = fold (\x y -&gt; x * 3 + y) 0
<br />也就是说,列表中所有元素的和乘以 3 ,等于每个元素乘 3 再求和。
<br />
<br />这个结论人脑想很浅显,但机器想就不是这回事了。
<br />fold 的这个性质给机器推理提供了新的方法。
<br />
<br />一些算法写出来简单易读,但是运行效率很低。利用这个性质进行变换,可以在不影响可读性的前提下优化算法。
<br />ghc 里面就有不少这样的优化。
<br />
<br />----------------------------------------------------------------------------
<br /><strong><span style="color: #0033FF;">“切香蕉”性质(banana split property of fold)</span></strong>
<br /><span style="color: gray;">梅姐 good job!</span>
<br />
<br />假设我们要计算和、平方和、立方和
<br /><pre name="code" class="haskell">sum'squareSum'cubicSum l = (sum l, squareSum l, cubicSum l)</pre>
<br />这样我们要遍历这个 list 3 遍。(这个问题在 C++ 模板编程中也经常遇到呢)
<br />
<br />但是用 fold 就不一样了:
<br /><pre name="code" class="haskell">sum'squareSum'cubicSum =
foldr (\x (s1, s2, s3) -&gt; (s1 + x, s2 + x ^ 2, s3 + x ^ 3)) (0, 0, 0)</pre>
<br />
<br />----------------------------------------------------------------------------
<br /><strong><span style="color: #0033FF;"> 源生递归 = fold </span></strong>
<br />在递归神教的教义中可以找到源生递归(primitve recursion)的通用模式:
<br /><pre name="code" class="haskell">
h y [ ] = f y
h y (x : xs) = g y x xs (h y xs)</pre>
<br />
<br />假定递归函数如上式定义,取出 f 和 g,然后用 fold 定义 k 如下:
<br /><pre name="code" class="haskell">
k y = fold i j
where
i x (z, xs) = (g y x xs z, x : xs)
j = (f y, [])
</pre>
<br />
<br />最后,我们得到的 k 是这么一个东西,它满足:
<br /><pre name="code" class="haskell">k y xs == (h y xs, xs)</pre>
<br />
<br />于是…… 万物至 fold …… (也不尽然,像 Ackman 函数那样的高阶递归就不能轻易的写成 fold)
<br />
<br />由于 fold 已经自带边界条件,所以用 fold 表达的函数不用写两行:
<br /><pre name="code" class="haskell">
--组合 list 内的所有函数
compose = foldr (.) id
</pre>
<br />
<br />foldl 也可以用 foldr 表示:
<br /><pre name="code" class="haskell">
foldl f v xs = fold (\x g -&gt; (\a -&gt; g (f a x))) id xs v
</pre>
<br />
<br />可惜如果不引入递归,foldr 没法用 foldl 表示——这也体现了命令式的循环的弱点。
<br />
<br />-----------------------------------------------------------------------------
<br /><strong><span style="color: #0033FF;">推荐 paper: </span></strong>
<br /><a target="_blank" href="http://www.cs.nott.ac.uk/~gmh/fold.pdf">http://www.cs.nott.ac.uk/~gmh/fold.pdf</a>
用 Ruby 踩踩四人帮
上上周在书店看到一本《Ruby设计模式》,捡起来 10 分钟看完,扔了(别问我为什么……)
<br />
<br />下面用 Ruby 写写设计模式,顺便批一批 Java 和 Gof。
<br />
<br />1.<a target="_blank" href="http://en.wikipedia.org/wiki/Factory_pattern">Factory</a> 和 Abstract Factory
<br /><pre name="code" class="Ruby">class Factory
attr_accessor :product
def produce
@product.new
end
end
class Product
#..
end
fac = Factory.new
fac.product = Product
fac.produce</pre>
<br />
<br />Java写的工厂有这么简单,这么容易重用么?
<br />
<br />2.<a target="_blank" href="http://en.wikipedia.org/wiki/Builder_pattern">Builder</a>
<br /><pre name="code" class="Ruby"># 工头
class Director
def build_with builder
acc = ''
[:header, :body, :footer].each do |m|
acc += builder.__send__ m if builder.respond_to? m
end
acc
end
end
# 工人
class HTMLBuilder
def header; '&lt;html&gt;&lt;title&gt;html builder&lt;/title&gt;';end
def body; '&lt;body&gt;html builder&lt;/body&gt;' ;end
def footer; '&lt;/html&gt;' ;end
end
class XMLBuilder
def header; '&lt;?xml version="1.0" charset="utf-8"&gt;';end
def body; '&lt;root&gt;xml builder&lt;/root&gt;' ;end
end
d = Director.new
puts(d.build_with HTMLBuilder.new)
puts(d.build_with XMLBuilder.new)
</pre>
<br />注意:Ruby的工序并不依赖于Builder的类,只要有方法签名就行了。
<br />interface 这种束手束脚,加强耦合的东西完全不需要~
<br />
<br />3.<a target="_blank" href="http://en.wikipedia.org/wiki/Prototype_pattern">Prototype</a>
<br />依样画葫芦。
<br />这里用一点 trick (evil ruby):
<br /><pre name="code" class="ruby">require 'evil'
class Prototype
# ...
end
class Concrete
include Prototype.as_module
end</pre>
<br />
<br />4.<a target="_blank" href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a>
<br />Ruby 包装方法易如反掌:
<br /><pre name="code" class="Ruby">class Adaptee
def talk; puts 'Adaptee';end
end
class Adapter &lt; Adaptee
alias talkee talk
def talk
puts 'before Adaptee'
talkee
puts 'after Adaptee'
end
end
Adapter.new.talk</pre>
<br />
<br />很多没学过设计模式的 Ruby 程序员天天用 adapter……
<br />
<br />5.<a target="_blank" href="http://en.wikipedia.org/wiki/Composite_pattern">Composite</a>
<br />这个 pattern 是给没有多重继承又没法 mixin 的语言用的。
<br />Ruby 只需要 include module。
<br />
<br />6.<a target="_blank" href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</a>
<br /><pre name="code" class="Ruby">module Colorful
attr_acessor :color
end
class Widget
end
w = Widget.new # w 作为 Widget 的实例,没有 color 方法
w.color = 'blue' rescue puts 'w has no color'
w.extend Colorful # 现在 w 有 color 方法了
w.color = 'blue'
puts w.color</pre>
<br />
<br />可怜的 Java 程序员需要学习设计模式才能写出 decorator。
<br />
<br />7.<a target="_blank" href="http://en.wikipedia.org/wiki/Flyweight_pattern">Flyweight</a>
<br /><pre name="code" class="Ruby"># 重量级对象的瘦身法:如果创建参数相同,则返回同一个对象
class FlyweightFactory
class Glyph
def initialize key
@key = key
sleep 1 # 睡一秒,以体现这个对象创建的“重量级”
@square = key ** 2
@cubic = key ** 3
end
attr_reader :key, :square, :cubic
end
def produce key
@glyphs ||= {}
@glyphs[key] || (@glyphs[key] = Glyph.new key)
end
end
ff = FlyweightFactory.new
g1 = ff.produce 2
g2 = ff.produce 2
puts (g1.object_id == g2.object_id)</pre>
<br />
<br />不得不说 || 是很爽的语法。
<br />另外 Ruby 的 Hash 可以用数组作 key,如果 Glyph 的构造函数需要更多参数,只需要把 produce 里的 key 改成 *key
<br />
<br />8.<a target="_blank" href="http://en.wikipedia.org/wiki/proxy_pattern">Proxy</a>
<br />Proxy 和 Adapter 的区别只在接口上,它们在 Ruby 中是一样的。
<br />这说明了:1.大道至简; 2.Gof 模式的语言局限性。
<br />
<br />9.<a target="_blank" href="http://en.wikipedia.org/wiki/Chain_of_responsibility_pattern">Chain of Responsibility</a>
<br />如果没有 proc,代码是做不到这么清晰简洁的:
<br /><pre name="code" class="Ruby">class Chain
def initialize
@chain = []
end
def add_handler &amp;block
@chain &lt;&lt; block
end
def handle req
@chain.each do |e|
# 如果handler返回 false(未处理),则让下一个处理
result = e[req]
return result if result
end
false
end
end
c = Chain.new
c.add_handler {|req| req == 1 ? "1:handled" : puts "1:not my responsibility" }
c.add_handler {|req| req == 2 ? "2:handled" : puts "2:not my responsibility" }
puts(c.handle 1)
puts(c.handle 2)</pre>
<br />
<br />10.<a target="_blank" href="http://en.wikipedia.org/wiki/Command_pattern">Command</a>
<br />本质:一次调用可以同时执行多个方法。GUI 编程中处理事件很常用。
<br />因为 Java 不能直接传递方法,所以把简单的问题复杂化了……
<br />btw:真不理解 swing 优美在哪里……
<br /><pre name="code" class="Ruby">class Command
def initialize
@executors = []
end
# 另一种方法是让 executors 保存一组对象,每个都带 execute 方法
# ——但是这么简单的事情就需要一组接口,一组实现?
def add_executor &amp;block
@executors &lt;&lt; block
end
def execute
@executors.each {|x| x.call }
end
end
c = Command.new
c.add_executor{ puts 'executor 1' }
c.add_executor{ puts 'executor 2' }
c.execute
</pre>
<br />Command 是和 Chain 很相似的东西,可能某天会有人写一本 "Pattern of Patterns" 吧。
<br />
<br />11.<a target="_blank" href="http://en.wikipedia.org/wiki/Template_method_pattern">Template Method</a>
<br />Java 一说模板,C++ 和 Ruby 就笑了。
<br />例(偷懒“重用”一下写过的代码):
<br /><pre name="code" class="Ruby"># 穷举法检验 de Morgan 定理
class Fixnum
%w[a1 a2 a3 b1 b2 b3].each_with_index do |name, idx|
define_method name, do
self &amp; (1&lt;&lt;idx) == 0 ? false : true
end
end
end
0b1000000.times do |n|
n.instance_eval %q[
if !((a1&amp;&amp;b1) || (a2&amp;&amp;b2) || (a3&amp;&amp;b3)) != !(a1&amp;&amp;b1) &amp;&amp; !(a2&amp;&amp;b2) &amp;&amp; !(a3&amp;&amp;b3)
puts 'blah'
end
]
end</pre>
<br />
<br />12.Iterator 和 Visitor
<br />这些模式还是作古吧。
<br />有太多简单的方式进行迭代(map, inject, each, each_with_index,sort ...)
<br />关键点还是语言对泛型和匿名函数的支持。
<br />
<br />13.<a target="_blank" href="http://en.wikipedia.org/wiki/Mediator_pattern">Mediator</a>
<br />将各个类的相互依赖性扔到一个中介类之中。
<br />老老实实的写个中介类?大概会像这样:
<br /><pre name="code" class="Ruby">class Mediator
def initialize seller, buyer
@seller = seller
@buyer = buyer
end
def sell
@seller.sell
end
def buy
@buyer.buy
end
end</pre>
<br />发现问题了吗? Mediator 出现的根源还是静态类型(是不会推断的那种)带来的耦合。
<br />Duck Typing (check respond_to? instead of class) 早已解耦,根本不需要中介。
<br />
<br />14.<a target="_blank" href="http://en.wikipedia.org/wiki/Strategy_pattern">Strategy</a>
<br />提供运行时选择策略(算法)的可能。
<br />假设 Array 有两种方法:bubble_sort 和 quick_sort
<br />按照 Gof 的教诲,我们可能会这样想:
<br /><pre name="code" class="Ruby">class Array
def sort options
if options[:strategy].to_sym == :bubble_sort
bubble_sort()
elsif options[:strategy].to_sym == :quick_sort
quick_sort()
end
end
end
arr.sort :strategy =&gt; strategy
</pre>
<br />根本就是没事找事……看看 Ruby 动态选择调用方法多简单:
<br /><pre name="code" class="Ruby">arr.__send__ strategy</pre>
<br />
<br />15.<a target="_blank" href="http://en.wikipedia.org/wiki/Singleton_pattern">Singleton</a>
<br /><pre name="code" class="Ruby">module SingletonClass
class &lt;&lt; self
# methods
end
end</pre>
<br />听说有人用两百行实现了严格的 singleton,膜拜中。
<br />
<br /><span style="color: white;">结论:
<br />如果没有类型声明和继承,很多依赖性都会消失无踪,接口也无用武之地了。
<br />设计模式大都是 Interface Hack 汇总,枯燥无味、思想僵化、限制创造力,早该下架了。
<br />学设计模式不如学 Ruby Python。
<br />Java 语言(注意不是平台)的弱点导致大量的冗余代码。
<br />所谓从善如流,有功夫写冗余代码不如多写几个测试。
<br />Java 语言(注意不是平台)的历史意义在于:将程序员从过早考虑效率的传统中解放了出来,现在也该功成身退了。</span>
<br />
<br />
SQL 与函数式编程
SQL 不愧是关系代数的产物,写出来就是赤果果的函数式编程。
<br />看这个语句:
<br /><pre name="code" class="sql">select * from topics where id &lt; 12</pre>
<br />
<br />把 topics 表看做一个 list,对应的命令式写法就像这样:
<br /><pre name="code" class="java">List&lt;Topic&gt; searchResult = new ArrayList&lt;Topic&gt;();
for(Topic topic : topics){
if(topic.id &lt; 12){
searchResult.add(topic);
}
}
return searchResult;</pre>
<br />
<br />但 select 本质上就是 filter 语句,在 Haskell 中可以写成:
<br /><pre name="code" class="haskell">filter (\x -&gt; (id x) &lt; 12) topics</pre>
<br />
<br />或者:
<br /><pre name="code" class="haskell">[x | x &lt;- topics, (id x) &lt; 12]</pre>
<br />
<br />而在 ActiveRecord 中对应查找方式是:
<br /><pre name="code" class="ruby">Topic.find :all, :conditions =&gt; ["id &lt; ?", 12]</pre>
<br />
<br />比较令人不爽,写成下面这样不好多了? 这才是 SQL DSL 嘛。
<br /><pre name="code" class="ruby">Topic.select(:all){ :id &lt; 12 }</pre>
<br />
<br />设想:将 block 解析成为 <a target="_blank" href="http://en.wikipedia.org/wiki/S-expression">s-exp</a>,然后翻译成 SQL 字符串。(s-exp 是一个数组套数组的结构,写出来就像 Lisp 程序一样,很适合用来做代码转换或者求值)
<br />
<br />这里提一提 ruby 中实现 s-exp 的简单原理:
<br />在一个新对象中对 block 求值,通过此对象的 method_missing 方法产生数组:
<br /><pre name="code" class="ruby">def method_missing meth, *args
[meth, args]
end</pre>
<br />实际上要复杂一些,还要反定义一些核心类的操作符等。(更全面、充分、快速的就要用到 parse tree 库了)
<br />
<br />基本可用的一个 sxp.rb 如<a target="_blank" href="http://www.iteye.com/topics/download/e410c38a-e302-38e5-8a4b-6cd3a1ab8e1c">附件(by Robin Stocker)</a>。尝试一下:
<br /><pre name="code" class="irb">irb(main):001:0&gt; require 'sxp.rb'
=&gt; true
irb(main):002:0&gt; id_max = 12
=&gt; 12
irb(main):003:0&gt; sxp{:id &lt; id_max}
=&gt; [:&lt;, :id, 12]</pre>
<br />
<br />工作良好,也能辨认闭包变量,再写一个 s-exp 到 sql string 的翻译器就行了。
<br />
<br /><pre name="code" class="ruby">class Symbol
def to_sql_method
{
:== =&gt; '=',
:_and =&gt; 'AND',
:_or =&gt; 'OR',
:_not =&gt; 'NOT'
}[self] || self
end
end
def build_sql arr
return arr.to_s unless arr.is_a? Array
meth = arr.shift
meth_s = meth.to_sql_method
params = arr.map {|e| build_sql e}
if params.empty?
"#{meth_s}"
elsif SxpGenerator::BINARY_METHODS.index meth
"(#{params[0]} #{meth_s} #{params[1]})"
else
"#{meth_s}(#{params.join ','})"
end
end
def Topic.select *options, &amp;block
Topic.find options, :conditions =&gt; build_sql(sxp &amp;block)
end
</pre>
<br />
<br />带 and 的使用方式:
<br /><pre name="code" class="ruby">Topic.select(:all){ _and(:id &lt; 12, :id &gt; 5) }</pre>
<br />
<br />这个实现比较 naive,不能辨认多行语句,and or 暂时只能前缀,也没有检查更多的 sql 函数……
<br />
<br />不过我的目的只是证明这种语法在 ruby 中是可以实现的。
<br />
<br />一般的数据库的使用方式是要通过 SQL 拼接的:
<br />逻辑 &lt;--&gt; ORM 框架、DAO 等 &lt;--&gt; SQL字符串 &lt;------&gt; 解析 SQL &lt;--&gt; 数据库 API 调用
<br />
<br />再进一步,对支持函数式编程的语言,为什么不直接一点,跳过生成 SQL 字符串这步呢?
<br />估计很多数据库操作的速度都会提升,也不会出现千奇百怪的 SQL 拼接法:
<br />逻辑 &lt;--&gt; 解析逻辑(语言编译器/解释器) &lt;------&gt;&nbsp; 数据库 API 调用
<br />
<br />补充: 看了 FX 的回帖,有点明白这个字符串形式调用的好处了。
<br />不过同一个进程/嵌入式的话,还是提供 select + 函数指针接口比较好呢。
不动点
简单的说,f 的不动点就是满足 f(x) = x 的值。(当然"值"也可以是函数)
<br />令 x = y f,那么在 Haskell 中可以写下 y 的定义:
<br /><pre name="code" class="haskell">y f = f (y f)</pre>
<br />
<br />Y-组合子最早是由 Haskell 发现的,除此之外还有其它不动点。
<br />
<br />不断展开可以看到 y f = f(f(f(f(...
<br />
<br /><img src="/upload/attachment/95461/2b761d11-4483-3006-8e22-cf91809c8883.png" />
<br />
<br />在 <a target="_blank" href="http://night-stalker.iteye.com/blog/366101">fold</a> 文中,一切递归形式都可以表达成 (<strong>foldr . 非递归函数</strong>)
<br />现在呢,一切递归也可以表达成 (<strong>不动点 . 非递归函数</strong>)。
<br />
<br />如阶乘函数
<br /><pre name="code" class="haskell">fac 1 = 1
fac n = n * (fac (n - 1))</pre>
<br />
<br />可以写成:
<br /><pre name="code" class="haskell">fac = y g where
g = (\f n -&gt; if n == 0 then 1 else n * f (n - 1))</pre>
<br />
<br />计算 fac 3 的过程如下:
<br /><pre name="code" class="haskell">fac 3
= y g 3 --fac
= g (y g) 3 --y
= 3 * (y g 2) --g
= 3 * (g (y g) 2) --y
= 3 * (2 * (y g 1)) --g
= 3 * (2 * 1) --g
= 6</pre>
<br />
<br />值得一提的是:这个实现是 haskell 算阶乘最快的…… 详见 <a target="_blank" href="http://www.willamette.edu/~fruehr/haskell/evolution.html">回字有几种写法</a>
<br />
<br />原因1:fix-point 是尾递,最终变成循环
<br />原因2:循环判定条件是 n /= 0,生成汇编会少一条指令
<br />
<br />继续了解不动点中…… 还得重温一点数学。
几点式? 无点式 (point-free style)
<p>跳译…… 原文见:</p>
<p><a target="_blank" href="http://www.haskell.org/haskellwiki/Pointfree" title="http://www.haskell.org/haskellwiki/Pointfree">http://www.haskell.org/haskellwiki/Pointfree</a></p>
<p> </p>
<p>函数式编程中,忽略接受的变量,将一个函数写成其它函数组合很常见。例如,这两个函数的功能是一样的:</p>
<pre name="code" class="haskell">sum = foldr (+) 0
sum' xs = foldr (+) 0 xs</pre>
<p> ...<br>
使用显式的点点往往使程序更清晰,如</p>
<pre name="code" class="haskell">let fn = f . g . h</pre>
<p> 就比</p>
<pre name="code" class="haskell">let fn x = f (g (h x))</pre>
<p> 好看。<br><br>
又一个例子:</p>
<pre name="code" class="haskell">--point-free map fusion
foldr f e . map g == foldr (f . g) e</pre>
<p> ...<br><br><span style="color: #3366ff;"><strong><span style="font-size: small;">1.但是呢,pointfree 用到的点更多……</span>
</strong>
</span>
</p>
<p><br>
一个常见的误会是:'pointfree' 风格的 'point' 指的是 (.) 算符。<br>
错! 这个词出自拓扑学。一个函数的 'pointfree' 定义,就是指:定义中不包含空间中的点(自变量,或者说,值)。<br>
Haskell 中,我们的 '空间' 是 type,'point' 是值。<br>
...<br>
额外两个例子:</p>
<pre name="code" class="haskell">f1 = (+ 1)
f2 = (1 +)</pre>
<p> </p>
<p><span style="color: #3366ff;"><strong><span style="font-size: small;">2.背景</span>
</strong>
</span>
</p>
<p> </p>
<p>...<br><br><span style="color: #3366ff;"><strong><span style="font-size: small;">3.支持工具</span>
</strong>
</span>
</p>
<p><br>
Thomas Yaeger: <strong>Lambdabot </strong>
(package pointfree)<br>
可以将函数声明写成 pointfree 形式(pl, point-less) 和 un-point-free 形式。<br>
示例<span style="color: #808080;">(漂亮和un漂亮)</span>
:</p>
<pre name="code" class="lambda bot">&gt; pl \x y -&gt; x y
id
&gt; unpl id
(\ a -&gt; a)
&gt; pl \x y -&gt; x + 1
const . (1 +)
&gt; unpl const . (1 +)
(\ e _ -&gt; 1 + e)
&gt; pl \v1 v2 -&gt; sum (zipWith (*) v1 v2)
(sum .) . zipWith (*)</pre>
<p> ...<br><br><span style="color: #3366ff;"><strong><span style="font-size: small;">4.探索组合子</span>
</strong>
</span>
</p>
<p><br><strong><span style="color: #3366ff;">4.1 猫头鹰</span>
</strong>
</p>
<p> </p>
<pre name="code" class="haskell">owl = ((.)$(.))</pre>
<p> 解释:</p>
<pre name="code" class="haskell">owl a b c d = a b (c d)</pre>
<p> 例:</p>
<pre name="code" class="haskell">&gt; ((.)$(.)) (==) 1 (1+) 0
True</pre>
<p><strong><span style="color: #3366ff;">4.2 点点</span>
</strong>
</p>
<p> </p>
<pre name="code" class="haskell">dot = ((.).(.))</pre>
<p>例:</p>
<pre name="code" class="haskell">sequence `dot` replicate ==
(sequence .) . replicate ==
replicateM
(=&lt;&lt;) == join `dot` fmap</pre>
<p><br><strong><span style="color: #3366ff;">4.3 晃</span>
</strong>
</p>
<p>...<br><span style="color: #808080;">没搞懂</span>
<br><br><strong><span style="color: #3366ff;">4.4 挤~果~酱~</span>
</strong>
</p>
<p> </p>
<pre name="code" class="haskell">f &gt;&gt;= a . b . c =&lt;&lt; g</pre>
<p>...<br><br><span style="color: #3366ff;"><strong><span style="font-size: small;">5.问题</span>
</strong>
</span>
</p>
<p>...<br><span style="color: #808080;">有时会导致搞不懂 /(ㄒoㄒ)/~~</span></p>
[Ruby 1.9] 鱼骨运算符
【根据 FX 的建议,正式命名为鱼骨运算符,&gt;-&gt; 长尾鱼骨,|-&gt; 为翻车鱼骨】
<br />
<br />Ruby 1.9 有一个改动:lambda 可以接受 proc。
<br />结合新的 lambda 语法: -&gt; x {...},我们可以做一些有趣的事情:譬如实现 Monad。
<br />
<br /><pre name="code" class="ruby">
# YOU ARE NOT SUPPOSED TO UNDERSTAND THIS
class Object
def return
-&gt; f {f[self]}
end
end
class Proc
# bind
def | f
call f
end
def un_return
call (-&gt; x {x})
end
def == p
(p.is_a? Proc) and (un_return == p.un_return)
end
# 方便的东西,可以把参数由[,,]变成[][][]
def -@
self.curry
end
end
</pre>
<br />
<br />这个“新”的运算符鱼骨(鱼头?) |---&gt; 其实是 | 和 - 和 -&gt; 的合体~~
<br />
<br />检验三律:
<br /><pre name="code" class="ruby">
m = 12.return
m |-&gt; x {x * 2} == 12 * 2
#=&gt; true
m |-&gt; x {x.return} == m
#=&gt; true
f = -&gt; x {(x * 2).return}
g = -&gt; x {x - 1}
(m | f) | g == m |-&gt; x {f.(x) | g}
#=&gt; true</pre>
<br />
<br />既然 Symbol#to_proc 作为标准写入了 ruby,看看这个:
<br /><pre name="code" class="ruby">m | :to_s.to_proc</pre>
<br />
<br />接着写一个 maybe Monad ? super easy !修改 return 的定义:
<br /><pre name="code" class="ruby">
class Object
def return mty = nil
if mty == :maybe
-&gt; f {nil? ? f[self] : nil}
else
-&gt; f {f[self]}
end
end
end
</pre>
<br />
<br />尝试一下:
<br /><pre name="code" class="ruby">
m = 12.return :maybe
m | :to_s.to_proc
#=&gt; "12"
m = nil.return :maybe
m | :to_s.to_proc
#=&gt; nil
</pre>
<br />
<br />但是 Maybe Monad 没什么作用,用 rescue nil 就可以达到同样的效果。
<br />而且由于返回了 nil,无法将状态传递下去,能传递下去的写法会非常非常复杂……
<br />
<br />一长串 Either Monad 适用的场景可以用简单的递归完成。
<br />
<br />注意定义里用了 [ ] 来 call 函数,我们可以传一个 array 或者 hash 、range 当做函数~~
<br /><pre name="code" class="ruby">
m = 3.return :maybe
arr = %w[a b c d]
m | arr
#=&gt; "d"
</pre>
<br />
<br />Array 形式的 pass on
<br /><pre name="code" class="ruby">m | arr.map(&amp;:return) |-&gt; x {print x}</pre>
<br />
<br />-&gt; x {print x} 很不爽吧,所以要改进:
<br />
<br /><pre name="code" class="ruby">class Proc
def | f
if f.is_a? Symbol
__send__ f, un_return
else
call f
end
end
def un_return
call (-&gt;x{x})
end
def == p
(p.is_a? Proc) and (un_return == p.un_return)
end
end
</pre>
<br />
<br />强大不?
<br /><pre name="code" class="ruby">
m | arr.map(&amp;:return) | :print
</pre>
<br />不强大。
<br />
<br />直接用 Proc 作 Monad 可能不太严谨,用个 Monad 包装可能这样要好点:(降低污染)
<br /><pre name="code" class="ruby">
class Monad &lt; Proc
...
</pre>
<br />
<br />==================================== 奇怪的分隔线
<br />
<br />List Monad 貌似更容易写
<br /><pre name="code" class="ruby">
class Array
def | f
if f.is_a? Symbol
(map {|e| __send__ f, e}).flatten 1
else
(map {|e| f[e]}).flatten 1
end
end
end
# return a : [a]
</pre>
<br />
<br />再次检验三律:
<br /><pre name="code" class="ruby">
m = [12]
m |-&gt; x {[x * 2]} == [12 * 2]
#=&gt; true
m |-&gt; x {[x]} == m
#=&gt; true
f = -&gt; x {[x * 2]}
g = -&gt; x {[x - 1]}
(m | f) | g == m |-&gt; x {f.(x) | g}
#=&gt; true</pre>
<br />
<br />这个貌似还有点用
<br /><pre name="code" class="irb">
&gt;&gt; def n x
&gt;&gt; [x+1,x+2]
&gt;&gt; end
&gt;&gt; [1] | :n
=&gt; [2, 3]
&gt;&gt; _ | :n
=&gt; [3, 4, 4, 5]
&gt;&gt; _ | :n
=&gt; [4, 5, 5, 6, 5, 6, 6, 7]
</pre>
<br />
<br />==================================== 奇怪的分隔线
<br />
<br />State Monad 是一个状态转移方程: -&gt; s { s, a }
<br />结果有点出乎意料…… 令人无比头痛的 State Monad 写起来真用不了几行:
<br />
<br /><pre name="code" class="ruby">class StateMonad &lt; Proc
def | f
StateMonad.new do |s0|
s1, a = self[s0]
f[a][s1]
end
end
end
class Object
def return_state
StateMonad.new {|s| [s, self]}
end
end
</pre>
<br />
<br />状态转移:
<br /><pre name="code" class="ruby">
# 注意这里用 - 将函数 curry 了
m = 3.return_state |--&gt; x, s {[s + 1, x * 2]}
state, val = m[0]
</pre>
<br />
<br />说到状态转移,可以用矩阵作转移函数! 设
<br /><pre name="code" class="ruby">t = Array.new(4) {|i|Array.new(4) {|j|[i, j]}}</pre>
<br />
<br />则:
<br /><pre name="code" class="ruby">
m = 3.return_state
(m | t | t | t)[0]
</pre>
<br />
<br />比下面的写法灵活呢:
<br /><pre name="code" class="ruby">
x, y = t[3][0]
x, y = t[x][y]
x, y = t[x][y]
</pre>
<br />
<br />==================================== 奇怪的分隔线
<br />
<br />总结: 各种 Monad 往往都有一个对应的 ruby 类:
<br />Unit&nbsp; - Proc
<br />List&nbsp; - Array
<br />Maybe - Object
<br />State - Proc
<br />
<br />历史:
<br />
<br /><a target="_blank" href="http://rednaxelafx.iteye.com/blog/347554">http://rednaxelafx.iteye.com/blog/347554</a>
<br />
<br /><a target="_blank" href="http://night-stalker.iteye.com/blog/349082">http://night-stalker.iteye.com/blog/349082</a>
<br />
GAE JRuby : links and notes
Google App Engine 支持 java 以后, 动作迅速的 Ola Bini 只花了一天,就把 JRuby 部署上去了。这是 Ola Bini 的原帖:
<br /><a target="_blank" href="http://olabini.com/blog/2009/04/jruby-on-rails-on-google-app-engine/">http://olabini.com/blog/2009/04/jruby-on-rails-on-google-app-engine/</a>
<br />
<br />jruby 最好用血淋淋的版本。它的版本库刚搬到 git 上面。可用下面两者之一:
<br />git://kenai.com/jruby~main
<br />git://github.com/jruby/jruby.git
<br />
<br />构建 jruby 要用 ant。 windows 下可以用比较傻的一个 ant:
<br /><a target="_blank" href="http://code.google.com/p/winant/">http://code.google.com/p/winant/</a>
<br />
<br />为了方便,可以弄个脚本设 jdk (jar) 和 ant 的路径,示例:
<br /><pre name="code" class="bat">
@set PATH=%PATH%;%JAVA_HOME%\bin;%ANT_HOME%\bin;D:\Develop\apache-maven-2.1.0\bin
@set CLASS_PATH=.;%JAVA_HOME%\lib\*.jar;
</pre>
<br />
<br />构建 jruby
<br /><pre name="code" class="console">
ant
ant jar-complete</pre>
<br />
<br />其它任务:
<br /><pre name="code" class="console">ant -p</pre>
<br />
<br />jruby-complete.jar 包含文件太多,需要拆。现成拆好的可以在 Ola 的 yarbl 里找:
<br /><a target="_blank" href="http://github.com/olabini/yarbl/tree/8681995b548860e2e13c90c4cf030fc682a32f34/lib">http://github.com/olabini/yarbl/tree/8681995b548860e2e13c90c4cf030fc682a32f34/lib</a>
<br />
<br />GAE 部署 sinatra 参考:
<br /><a target="_blank" href="http://blog.bigcurl.de/2009/04/running-sinatra-apps-on-google.html">http://blog.bigcurl.de/2009/04/running-sinatra-apps-on-google.html</a>
<br />
<br />sinatra 是什么? 你可以访问 JavaEye 的 ruby off rails 圈子看看,也可以花上 30 分钟看看这个视频:
<br /><a target="_blank" href="http://rubyconf2008.confreaks.com/lightweight-web-services.html">http://rubyconf2008.confreaks.com/lightweight-web-services.html</a>
<br />
<br />sinatra 非常简单,上手巨快,可以只用 200 多行写一个 wiki……
<br />核心思想: Exposed simplicity over hidden complexity
<br />
<br />关键的 rack for jruby 也不能少(其实用 Ola 给的 jruby-rack.jar 就可以了):
<br /><a target="_blank" href="http://github.com/nicksieger/jruby-rack/tree/master">http://github.com/nicksieger/jruby-rack/tree/master</a>
<br />
<br />Net::HTTP 的 monkey patch 及 User Service、Memcache support:
<br /><a target="_blank" href="http://github.com/lstoll/rb-gae-support/tree/master">http://github.com/lstoll/rb-gae-support/tree/master</a>
<br />
<br />DataMapper 的 Datastore Adapter:
<br /><a target="_blank" href="http://github.com/genki/dm-datastore-adapter/tree/master">http://github.com/genki/dm-datastore-adapter/tree/master</a>
<br />
<br />各种设置的样板文件:
<br /><a target="_blank" href="http://gist.github.com/91801">http://gist.github.com/91801</a>
<br />
<br />========================================= 下面是 Notes
<br />
<br />拆 jruby-complete.jar 的脚本—— windows 版
<br /><pre name="code" class="bat">
@del /F /Q jruby-core.jar
@del /F /Q ruby-stdlib.jar
@rd /S /Q tmp_unpack
@md tmp_unpack
@cd tmp_unpack
@jar xf ../jruby-complete.jar
@cd ..
@md jruby-core
@move tmp_unpack/org jruby-core/
@move tmp_unpack/com jruby-core/
@move tmp_unpack/jline jruby-core/
@move tmp_unpack/jay jruby-core/
@move tmp_unpack/jruby jruby-core/
@cd jruby-core
@jar cf ../jruby-core.jar .
@cd ../tmp_unpack
@jar cf ../ruby-stdlib.jar .
@cd ..
@rd /S /Q jruby-core
@rd /S /Q tmp_unpack
@del /F /Q jruby-complete.jar
</pre>
<br />
<br />warbler 0.9.12 有点问题,用简单粗暴的手段解决:
<br />打开 <pre name="code" class="java">%jruby_home%\lib\ruby\gems\1.8\gems\warbler-0.9.12\bin\warbler</pre>
<br />将 57 行改成
<br /><pre name="code" class="ruby">system "jruby -S gem unpack warbler"</pre>
<br />
<br />rake 也会卡你,打开 <pre name="code" class="java">%jruby_home%\lib\ruby\gems\1.8\gems\rake-0.8.4\lib\rake\repaired_system.rb</pre>
<br />将 109 行的 <pre name="code" class="java">*ENV["PATH"]</pre> 改成 <pre name="code" class="java">*(ENV["PATH"] || '')</pre>
<br />
<br /><strong>切记: jruby 和 netbeans 的摆放路径千万不能含空格和汉字。</strong>
<br />虽然 jruby 号称解决这个问题了,但还是小心的好……
<br />
<br />Active Record 用不了。
<br />
<br />打包 gem 成 jar 的示例(作用不大)
<br /><pre name="code" class="console">
jruby -S gem install -i ./rails rails --no-rdoc --no-ri
jar cf rails.jar -C rails .
</pre>
<br />
<br />==================================================== 结果
<br />
<br />我用 sinatra 做了一个简单的 hello 骨架:
<br /><a target="_blank" href="http://indekus.appspot.com">http://indekus.appspot.com</a>
<br />
<br />此骨架的源代码和各种 jar 已经传到 google code, 可以用 svn 拖下来:
<br /><pre name="code" class="console">
svn checkout http://gaesk.googlecode.com/svn/trunk/ gaesk-read-only
</pre>
<br />
<br />
[Ruby 1.9] 超箭头运算符
首先你需要 Ruby 1.9 ,然后
<br /><pre name="code" class="ruby">class Proc; def -@; self; end; end</pre>
<br />
<br />试一下:
<br /><pre name="code" class="ruby">p = ------------------&gt; x{x + 1}
p[1]</pre>
<br />
<br />have fun.
<br />
<br />
<br /><span style="color: red;">----------------------------&gt;</span>
<br /><span style="color: cyan;">--------------------------------------------------------------------------------------&gt; </span>
<br /><span style="color: violet;">-------------------------------------------------&gt;</span>
<br /><span style="color: orange;">&lt;------------------------------------------------------------------------------------------------------</span>
<br />
<br />
<br />
<br />有个更舒服的做法:
<br />gem install superators
<br />
<br /><div class="quote_title">Jay Phillips 写道</div><div class="quote_div">
<br /><pre name="code" class="ruby">require 'superators'
class Array
superator "&lt;-----------------" do |operand|
self &lt;&lt; operand.reverse
end
end
[1,2,3] &lt;----------------- [1,2,3]
#=&gt; [1,2,3,3,2,1]
</pre>
<br /></div>
<br />
<br />注意,和上面不同,多一个减号或者少一个都不成立哦。
<br />
<br />Jay Phillips 是 Rails 后另一个杀手级应用 Adhearson 的作者。
模板语言:蛤蟆 ( haml )
haml —— XHTML Abstraction Markup Language
<br />
<br />此文是熟悉 haml 时写的,一片凌乱。
<br />想看整洁漂亮、人性易懂、深入浅出的介绍请访问官网
<br /><a target="_blank" href="http://haml.hamptoncatlin.com/">http://haml.hamptoncatlin.com/</a>
<br />嗯,还有 DHH 当托 -____- |||
<br />
<br />开始:(安装时如果生成 rdoc 或者 ri 会出错)
<br /><pre name="code" class="java">gem install haml --no-rdoc --no-ri
haml --rails your_rails_app_home/app</pre>
<br />
<br />sinatra 天生支持:
<br />把 xxx.haml 扔到 views 目录里
<br /><pre name="code" class="java">haml :xxx</pre>
<br />就是这么简单!连config,require 都不用!
<br />
<br />除了和 web 框架集成,平时也可单独使用:(用法就和 ERB 差不多)
<br /><pre name="code" class="java">require 'rubygems'
require 'haml'
engine = Haml::Engine.new "%p Haml code!"
engine.render #=&gt; "&lt;p&gt;Haml code!&lt;/p&gt;\n"</pre>
<br />
<br />======================================== 语法
<br />
<br />基本语法:我认为下面两个例子是自明的……
<br /><pre name="code" class="java">%strong#message hello world
%strong.content.code= "hello world"</pre>
<br />
<br />%div 可以省略,大括号中的 hash 会转换成 xhtml 的属性
<br /><pre name="code" class="java">.item{:id =&gt; "item#{item.id}",
'style' =&gt; 'background-color:yellow'}= item.body</pre>
<br />
<br />缩进 == 嵌套
<br /><pre name="code" class="java">#content
.left.column
%h2= post.title
%p= post.content
.right.column= render :partial =&gt; "sidebar"</pre>
<br />
<br />如 erb 一样,可以访问 controller 的实例变量
<br />
<br />snippet 一个:
<br /><pre name="code" class="java">%html{:xmlns=&gt;"http://www.w3.org/1999/xhtml"}</pre>
<br />
<br />心理有障碍的…… 哦不,自闭的标签
<br /><pre name="code" class="java">%sandwich/</pre>
<br />
<br />聪明的省略:
<br /><pre name="code" class="java">%input{:selected=&gt;true}
#=&gt; &lt;input selected='selected'&gt;
%input{:selected=&gt;false}
#=&gt; &lt;input&gt;</pre>
<br />
<br />[a, b] 规则:
<br />class 为 cls = "#{b}#{'_' if b}#{a.class}".downcase
<br />id&nbsp;&nbsp;&nbsp; 为 "#{cls}_#{a.id}"
<br />设 @u = User.find 1,则
<br /><pre name="code" class="java">%div[@u, :name]</pre>
<br />产生
<br /><pre name="code" class="java">&lt;div class="name_user" id="name_user_1"&gt;</pre>
<br />而
<br /><pre name="code" class="java">%div[2]</pre>
<br />产生
<br /><pre name="code" class="java">&lt;div class="fixnum" id="fixnum_324"&gt;</pre>
<br />
<br />消灭标签外/内部前后的空格: &gt; &lt;
<br />如:
<br /><pre name="code" class="java">%p&lt;= "ha\nha"</pre>
<br />将会产生
<br /><pre name="code" class="java">&lt;p&gt;ha
ha&lt;/p&gt;</pre>
<br />&gt;&lt; 可以一起用
<br />
<br />~ "foo" 就是 =find_and_preserve "foo"
<br />
<br />======================================== helper
<br />生成 xml 指令和 doctype 指令
<br /><pre name="code" class="java">!!! XML
!!! 1.1</pre>
<br />
<br />指令还有
<br /><pre name="code" class="java">!!! Strict
!!! Basic
!!! Mobile</pre>
<br />
<br /><pre name="code" class="java">/ html comment</pre>
<br />产生(单行)comment
<br /><pre name="code" class="java">&lt;!-- html comment --&gt;</pre>
<br />
<br /><pre name="code" class="java">/
%p doesn't render</pre>
<br />产生多行comment
<br /><pre name="code" class="java">&lt;!--
&lt;p&gt;doesn't render&lt;/p&gt;
--&gt;</pre>
<br />
<br /><pre name="code" class="java">\</pre>
<br />转义一行的首字符
<br />
<br /><pre name="code" class="java">|</pre>
<br />置于行尾,连接多行字符
<br />
<br /><pre name="code" class="java">:some_filter</pre>
<br />(注意后面的行要缩进) 已定义的 filter 包括
<br />plain, javascript, escaped, ruby, preserve, erb,
<br />sass, textile, markdown, maruku
<br />
<br />多行 =
<br /><pre name="code" class="java">%p
= ['ho','hi'].join ' '
= 123</pre>
<br />设置 :escape_html 选项后,所有 = 语句都会转义
<br />
<br /><pre name="code" class="java">-</pre>
<br />对 ruby 代码求值但不输出
<br />
<br />== interpolates rb code into plain txt,如
<br /><pre name="code" class="java">%p== This is #{h quality} cake!</pre>
<br />这时 \ 可以转义 #{}, 但是 \ 本身不转义,如
<br /><pre name="code" class="java">%p== \\ no \#{yes}</pre>
<br />产生
<br /><pre name="code" class="java">&lt;p&gt;\\ no #{yes}&lt;/p&gt;</pre>
<br />
<br /><pre name="code" class="java">&amp;=</pre>
<br />输出前将右边内容转义,如果设了 :escape_html,则同 =
<br />
<br /><pre name="code" class="java">!=</pre>
<br />不将右边内容转义,如果不设 :escape_html, 则同 =
<br />
<br />block~~~~ 风格很 python ...
<br /><pre name="code" class="java">- (1..100).each do |i|
%p= i</pre>
<br />
<br /><pre name="code" class="java">-# single line comment
-#
multi line comment
nor will this line display</pre>
<br />
<br />======================================== 选项设置
<br /><pre name="code" class="java">Haml::Template.options[:format] = :html5
</pre>
<br />这条有点帅,但是 w3c.org 自己都通不过 html5 检验呢(format 默认 xhtml)
<br />
<br />在 sinatra 设置要简单一些
<br /><pre name="code" class="java">set :format, :html5</pre>
<br />
<br />其它选项
<br />:escape_html, :suppress_eval ……
<br />
<br />======================================== haml2other
<br />
<br />以前看到一个帖子说 haml 是美工的噩梦?你可以在命令行运行 haml 输出 html:
<br /><pre name="code" class="java">haml in.haml out.html</pre>
<br />
<br />记住这些东西: css2sass, html2haml, sass2css, haml2html 对团队协作非常有意义。
<br />
<br />用蛤蟆产生 erb -- 只需 9 行代码,不难吧?
<br /><a target="_blank" href="http://gist.github.com/17371">http://gist.github.com/17371</a>
<br />
<br />蛤蟆标签的 id 和 class 完全是 css 选择器形式,看起来很直观,
<br />如果你们的美工肯花 20 分钟看 tutor,那就没障碍了,erb 可以让他们更抓狂吧……
<br />当然有人不同意以上看法(他认为是 2 分钟)。
<br />
<br />似乎还没 IDE 支持。但 haml 趋近于精简的极点,能让 IDE 自动完成的东西都让 haml 咔嚓掉了……
<br />或许不久后有爱人士会弄一个可以画的…… 不过画的速度肯定没打字的快。
<br />不过我想 haml 的 IDE 很容易做。
<br />
<br />查看命令行 haml 的更多选项:
<br /><pre name="code" class="java">haml -help</pre>
<br />
<br />======================================== 一些链接
<br />
<br />不相信可读性提高的,可以看这个例子:
<br /><a target="_blank" href="http://vivimusing.iteye.com/blog/324845">http://vivimusing.iteye.com/blog/324845</a>
<br />
<br />reddit 上关于 haml 和 sass 的口水仗(老外还有整个团队使用 haml + sass + compass 的,这对从众不从良的中国人太困难了……)
<br /><a target="_blank" href="http://www.reddit.com/r/web_design/comments/88dy7/what_is_your_opinion_of_writing_hamlsass_as/">http://www.reddit.com/r/web_design/comments/88dy7/what_is_your_opinion_of_writing_hamlsass_as/</a>
<br />
<br />======================================== 某些感想
<br />
<br />要达到更高的思考/工作效率,速记法和黑话是必不可少的,不过满屏黑话也会让人望而生畏……
<br />虽然这些定义很简单,学起来很快,结果也很清晰,但是让人产生恐惧心理就影响推广了。
<br />
<br />注意等号前面不能有空格,否则就当普通行处理。
<br />
忽悠名词小汇
忽悠名词是这么一些东西:它们都不是一句话,或者一小段话能说明白的概念(事实上没人能说明白……)。
<br />维特根斯坦老爹根本不鸟这类模糊的概念("我是谁"、"生命的意义"等等……)。
<br />萧老师说我们生产新东西,一定要 "well-defined"(可是商业社会想赚钱还得靠忽悠)。
<br />
<br />小修小改,云山雾罩。列举一些 buz words 和其近义词如下 ↓
<br />
<br />中间件(middleware):外挂的拦截器
<br />
<br />网格(grid)计算:封装的分布式计算
<br />
<br />云计算:大规模的网格计算
<br />
<br />架构:没代码的程序
<br />
<br />架构师:UML 程序员
<br />
<br />面向服务(SOA):非面向对象
<br />
<br />领域(domain):要解决的问题
<br />
<br />商业智能(BI):抓主意小工具
<br />
<br />
<br />胡乱组合也是忽悠技巧之一。
<br />譬如有人说“云计算不是简简单单的网格!”,问他到底是什么他又答不出来,只说概念很广泛,还“结合了 SaaS,PaaS,……”,而且不是简单组合,而是“有机整合”……
<br />
<br />数学中有一个思想是求同:把问题同构映射到我们熟悉的数学结构上,往往就能充分利用前人的智慧,解决这个问题。
<br />但是忽悠有个思想是求异:一定要忽略本质上相同的东西,强调皮毛上不同的东西,让人产生一种“完完全全是新东西”的感觉。
如何放弃 OOP
在 FX 的 blog 中,有个<a target="_blank" href="http://rednaxelafx.iteye.com/blog/245022">小寓言</a>,大致就是讲:
<br />“object 是傻蛋的 closure, closure 是傻蛋的 object。”
<br />
<br />从 OOP 到 FP 的转变不复杂,就如 rebol 控啫喱君所说:
<br /><div class="quote_title">啫喱君 写道</div><div class="quote_div">
<br />&nbsp;&nbsp; 1. 將Object為主的程式碼轉回Procedure的方式:將Object化成Record,將Method轉成Function,將this(或self)當作Function的參數,把Function集中放到Module(模組)。
<br />
<br />&nbsp;&nbsp; 2. 將程式中用到迴圈的地方,盡量轉成遞迴(Recursion)。先不要管執行效率的問題。
<br />
<br />&nbsp;&nbsp; 3. 將程式中用到if/else或switch/case的地方,改用Pattern Matching(模式比對)。
<br />
<br />只要做到上述這三件事,你的F#程式會具有濃濃的FP風味。</div>
<br />
<br />这里的 F#,是 Haskell 的兄弟。
<br />
<br />================================================ Haskell 类型系统小小探
<br />
<br /><span style="font-size: x-large;"><span style="color: blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance = class X data</span></span>
<br />
<br />注意 haskell 的 class 是类型的 class,而不是对象的 class。
<br />
<br />定义 <span style="color: red;"><strong>data</strong></span> 结构(即,定义数据类型)的两种方法:
<br /><pre name="code" class="haskell">--装箱法
data Point = Point Int Int deriving Show
--使用:
Point 3 5
map (Point 1) [1..5]
--Record法
data Point = Point { x::Int, y::Int } deriving Show
--使用:
p = Point {x = 3, y = 5}
--自动产生取属性函数:
x p
y p</pre>
<br />
<br />嵌套 ok,| 也 ok。 使用 | 和嵌套定义,可以得到灵活的可变类型。
<br />deriving 语句代表它是哪些 type class 的 instance。
<br />
<br />* 从多个 type class 派生: deriving (Ord, Eq)
<br />* type 语句:别名
<br />* newtype 语句:组合了 data 和 type
<br />
<br />type <span style="color: red;"><strong>class</strong></span> 就像接口一样,定义了一些行为,如:
<br /><pre name="code" class="java">class Eq a where
(==) :: a -&gt; a -&gt; Bool
(/=) :: a -&gt; a -&gt; Bool</pre>
<br />
<br />这些行为还没有绑定到数据结构中,可以通过 <span style="color: red;"><strong>instance </strong></span>语句“实现接口”
<br /><pre name="code" class="haskell">data Chicken = Cock | Hen
instance Eq Chicken where
Cock == Cock = True
Hen == Hen = True
_ == _ = False
</pre>
<br />
<br />* 由于 Prelude 所带的 Eq 实现中,== 是用 /= 定义的, /= 是用 == 定义的, 我们只需要在 instance 中定义其中一个就行了。
<br />
<br />deriving 和 instance 作用相似,不过 deriving 的函数都定义好了。
<br />
<br />总结下来,封装、继承、绑定、多态(甚至更高阶的多态)能做的,它都能做,也不用 new 啊 new 的,很清爽呢。
<br />
<br />================================================== 长舒一口气
<br />
<br />Functor 有入选“忽悠名词小汇”的潜质。
<br />它的作用其实很简单:穿透箱子。
<br /><pre name="code" class="haskell">class Functor f where
fmap :: (a -&gt; b) -&gt; f a -&gt; f b </pre>
<br />对付 Monad 的重重包装很有用。如:
<br /><pre name="code" class="haskell">instance Functor [] where
fmap = map </pre>
<br />
<br />================================================== what's more
<br />
<br />刚得了流感,不知道是不是猪流…… 意识模糊…… 大概还能活几天的吧……
<br />
<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 一些 link |
<br />
<br />
<br />很有爱的 --&gt; learn u a haskell for great good &lt;--
<br /><a target="_blank" href="http://learnyouahaskell.com/making-our-own-types-and-typeclasses">http://learnyouahaskell.com/making-our-own-types-and-typeclasses</a>
<br />
<br />Hindley/Milner 类型系统的一篇 paper:(具体网址找不到了,G 吧……)
<br />Functional Programming with Overloading and Higher-Order Polymorphism
<br />
<br />T1 的长文 Category Theory 和 Monad:
<br /><a target="_blank" href="http://www.iteye.com/post/428151?page=1">http://www.iteye.com/post/428151?page=1</a>
<br />
<br />啫喱君的不落格 &gt;&gt;= 言程序 =&lt;&lt;:
<br /><a target="_blank" href="http://jerrylovesrebol.blogspot.com">http://jerrylovesrebol.blogspot.com</a>
<br />
Ruby 静态编程 (你看错了……)
历史:Ruby 程序员干活特别轻松,干完活后闲着没事干,就到处鼓吹,所以动静态语言大战也此起彼伏,战得不亦乐乎,很多人也从中找到了活着的意义和生命的乐趣。 各种 troll 的新方式也被发掘出来,令广大反低俗的论坛管理员头痛不已。(什么是 troll 和 troll hunter 请自行人肉)
<br />
<br />也有一些人比战斗员们(我,我不是战斗员啦!<img src="/images/smiles/icon_redface.gif" /> )更闲,把两者揉到一起,发明了 <span style="font-size: large;"><strong>DRuby</strong></span>。
<br />世界上含有“D”的词一般都说“动态”,不过别误解这个“D”,它是 —— Diamondback。
<br />
<br />昨天(5月7日), On Ruby 上发表了一个关于 Diamondback Ruby 的<a target="_blank" href="http://on-ruby.blogspot.com/2009/05/diamondback-ruby-interview.html"> &gt;&gt;= 访谈 =&lt;&lt; </a>。
<br />(相关关键字: 静态类型推导,Ocaml)
<br />
<br /><div class="quote_title">Mike Hicks 写道</div><div class="quote_div">
<br />There is a long-discussed tension between statically (or explicitly)-typed languages like Java and dynamically (or implicitly)-typed languages like Ruby. My hope has been to discover how to include the best aspects of static and dynamic typing in a single language. We all really like Ruby's design and features, and felt it was the right language to start with. As we go, we'll look to derive general design principles that make sense for most any programming language, to simplify and improve the process of programming generally.</div>
<br />
<br />
<br />两位 Mike (兄弟?)还是花了很多心血的,甚至还发了 paper:
<br /><a target="_blank" href="http://www.cs.umd.edu/projects/PL/druby/papers/druby-oops09.pdf">http://www.cs.umd.edu/projects/PL/druby/papers/druby-oops09.pdf</a>
<br />
<br />主页传送门:
<br /><a target="_blank" href="http://www.cs.umd.edu/projects/PL/druby/index.html">http://www.cs.umd.edu/projects/PL/druby/index.html</a>
<br />
<br /><div class="quote_title">Overview 写道</div><div class="quote_div">
<br />Diamondback Ruby (DRuby) is an extension to Ruby that aims to bring the benefits of static typing to Ruby without compromising the expressiveness of the language. The main features of DRuby are:
<br />
<br />&nbsp;&nbsp;&nbsp; * Type inference: DRuby uses inference to model most of Ruby’s idioms as precisely as possible without any need for programmer intervention.
<br />
<br />&nbsp;&nbsp;&nbsp; * Type annotations: Methods may be given explicit type annotations with an easy to use syntax inspired by RDoc.
<br />
<br />&nbsp;&nbsp;&nbsp; * Dynamic checking: When necessary, methods can be type checked at runtime, using contracts to isolate and properly blame any errant code, similar to gradual typing.
<br />
<br />&nbsp;&nbsp;&nbsp; * Metaprogramming support: DRuby includes a combined static and dynamic analysis to precisely model dynamic meta-programming constructs, such as eval and method_missing.
<br /></div>
<br />
<br />Quick Start 传送门:
<br /><a target="_blank" href="http://www.cs.umd.edu/projects/PL/druby/quickstart.html">http://www.cs.umd.edu/projects/PL/druby/quickstart.html</a>
<br />
<br />小小例子(通过 Annotation 指定类型):
<br /><pre name="code" class="ruby">##% quack : () -&gt; String
def quack()
"quack!"
end
</pre>
<br />
Template in Haskell
使用 template,可以做强大的事情:
<br />编译期计算、实现可变参数个数的函数、更灵活的语法……
<br />Template Haskell 可缩作 TH。
<br />
<br />用法:
<br />$(tmpfunname p1, p2, ...)
<br />
<br />做法:
<br />module XXX where
<br />
<br />import language.Haskell.TH
<br />
Some cool fonts
<img src="/upload/attachment/105201/d38cd8f3-4e59-371a-97c2-7579e28ae33f.png" />
<br />
<br /><img src="/upload/attachment/105203/44300316-6a65-3949-a758-a4bfb7376632.png" />
<br />
<br />galactic basis 外星人字体译码表:
<br />
<br /><img src="/upload/attachment/105206/19ad3507-5b27-3c03-a0e6-4e452457b339.gif" />
<br />
<br />大写字母的中心对称图形便是小写字母
<br />
<br />下面三种字体分别是 Myst,Tolkein 矮人符语 (dwarf rune),Tolkein 精灵语:
<br />
<br /><img src="/upload/attachment/105314/1ab1cccd-784e-3e1b-a613-a9fea6d12823.jpg" />
<br />
VC 编写 Ruby Native Extension Notes
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">VC 工程设置</span>
</strong>
</p>
<p> </p>
<p>以 1.9.1 和 msvc 10 为例<br><br><span style="color: #3366ff;">
[c/c++ | additional include directories]</span>
<br>
include 目录添加<br>
    %ruby_home%\include\ruby-1.9.1<br>
    %ruby_home%\include\ruby-1.9.1\i386-mswin32_100</p>
<p>注意不要添加 include\ruby-1.9.1\ruby,里面有个 ruby.h 重名了<br><br><span style="color: #3366ff;">
[linker -&gt; general | additional library directories]</span>
<br>
lib 目录添加<br>
    %ruby_home%\lib<br><br><span style="color: #3366ff;">
[linker | additional dependancies]</span>
<br>
链接依赖的 lib 添加<br>
    msvc100-ruby191.lib<br>
如果用到 common control,添加</p>
<p>    comctl32.lib</p>
<p><br><span style="color: #3366ff;">
[general | configuration type]</span>
<br>
输出选择<br>
    dynamic library<br><br><span style="color: #3366ff;">
[general | target extension]</span>
<br>
输出文件扩展名改成<br>
    .so<br><br><span style="color: #3366ff;">
[general | character set]</span>
<br>
字符集转换都很麻烦,按经验,最好使用</p>
<p>    multibyte charset</p>
<p> </p>
<p>另:ruby 的入口点要和输出文件名相同,大小写敏感,如 aBc.so 对应 init_aBc<br>
如果是 cpp,入口点添加 extern "C" 修饰符。示例:</p>
<pre name="code" class="cpp">extern "C" void __declspec(dllexport) Init_aBc();</pre>
 
<p> </p>
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">建立窗口句柄 和 ruby object 之间的对应关系</span>
</strong>
</p>
<p> </p>
<p>用到的 API: <span style="color: #3366ff;"><strong><span>SetWindowLong </span>
</strong>
</span>
</p>
<p>windows 窗体有一个类型为 long 的 slot 可以存 user data,ruby obj 在 C 里面的类型是 VALUE (unsigned long)。</p>
<p><span style="color: #808080;"><em><span>关于 VALUE 如何对应 ruby 的各种类型,可参考 ruby hacking guide 或看 MRI 源代码。</span>
</em>
</span>
</p>
<p>虽然 unsigned long 和 long 有些区别,但只要 obj 不是直接量,VALUE 就对应其内存地址,而 32 位有符号整数,只用非负部分,寻址空间有 512G,不能表示的位置几乎不可能达到,所以可以放心互转并存入窗体结构中。</p>
<p> </p>
<p>将窗口句柄 h 和 ruby obj 对应起来,可以:</p>
<pre name="code" class="cpp">SetWindowLong(h, GWL_USERDATA, (long)obj);</pre>
 
<p>handle 同时也是一个整数,所以可以存到 obj 的属性中,假如存入 obj.h</p>
<pre name="code" class="cpp">rb_funcall(obj, rb_intern("h="), 1, LONG2NUM((long)h));</pre>
 
<p>存过以后,可以定义 handle 和 object 相互转换的宏</p>
<p> </p>
<pre name="code" class="cpp">inline VALUE HWND2VALUE(HWND h) {
long l = GetWindowLong(h, GWL_USERDATA);
return l ? (VALUE)l : Qnil;
}
inline HWND VALUE2HWND(VALUE v) {
VALUE res = rb_funcall(v, ID_h, 0);
return (res == Qnil) ? 0 : (HWND)NUM2LONG(res);
}</pre>
<p>ps:后来还是改用了一个中间结构。setwindowlong 存了个指针。</p>
<p> </p>
<p> </p>
<p><span style="color: #ff6600;"><strong><span style="font-size: medium;">用 ruby proc 进行消息处理</span>
</strong>
<br></span>
</p>
<p> </p>
<p>signal / slot 的方式很流行,但缺点是很慢,ruby 本来就很慢,这里再慢就更难受了。</p>
<p>我觉得用类 MFC 的消息映射宏比较好(实际上还要处理一些细节,不过无关主题,就省去了):</p>
<p> </p>
<pre name="code" class="cpp">#include &lt;map&gt;
// STL 的 map 内建红黑树. key 为窗口句柄, value 为 ruby proc
typedef std::map&lt;HWND, VALUE&gt; MAP;
#define BEGIN_MSG \
WNDPROC _old_proc = 0;\
LRESULT CALLBACK _new_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {\
switch(message) {
// connect msg and map : 通过句柄查找 proc,如果找到,就调用处理函数
#define CONNECT(msg, map) \
case msg:\
do{\
MAP::iterator v = map.find(hwnd);\
if(v != map.end()) {\
rb_funcall(v-&gt;second, rb_intern("call"), 1, HWND2VALUE(hwnd));\
return 0;\
}\
}while(0);\
break;
#define END_MSG \
}\
return CallWindowProc(_old_proc, hwnd, message, wparam, lparam);\
}</pre>
 
<p>一个定义 绑定左键点击的函数 (click_eq) 例子:</p>
<p> </p>
<pre name="code" class="cpp">namespace{
// 每消息一个 map
MAP map; // =Map();
BEGIN_MSG;
CONNECT(WM_LBUTTONDOWN, map);
END_MSG;
VALUE click_eq(VALUE self, VALUE proc) {
if(proc != Qnil)
map[VALUE2HWND(self)] = proc;
return proc;
}
... // 定义创建窗口等其它函数
}
... // 把 click_eq 绑定到 click= 方法</pre>
 
<p>ruby 的用法就像这样:</p>
<p> </p>
<pre name="code" class="ruby">obj.click= proc{|this| puts this}
</pre>
<p> </p>
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">装载外部字体</span>
</strong>
</p>
<p> </p>
<p>从 why 的 shoes 源代码中看到,超简单:</p>
<pre name="code" class="cpp">AddFontResource(StringValueCStr(path_str));</pre>
<p> </p>
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">win xp 风格的窗体控件</span>
</strong>
</p>
<p> </p>
<p>首先需要 common control。包括 #include &lt;commctrl.h&gt; 和 comctl32.lib</p>
<p>保证 common control 的 dll 加载:</p>
<pre name="code" class="cpp">INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES | ICC_BAR_CLASSES | ICC_STANDARD_CLASSES | ICC_USEREX_CLASSES;
InitCommonControlsEx(&amp;icex);
</pre>
 
<p> </p>
<p>这一行是必须的,摆在 stdafx.h 里头,#pragma once 下面。</p>
<pre name="code" class="cpp">#define ISOLATION_AWARE_ENABLED 1</pre>
<p> </p>
<p><span style="color: #0000ff;">[manifest tool -&gt; input and output | Additional manifest files]</span>
</p>
<p>添加</p>
<p>    ext.dll.manifest</p>
<p> </p>
<p>内容如下</p>
<pre name="code" class="xml">&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
&lt;assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&gt;
&lt;assemblyIdentity version="1.0.0.0" processorArchitecture="X86"
name="Ruby.Cici.ext" type="win32" /&gt;
&lt;description&gt;ext.so&lt;/description&gt;
&lt;dependency&gt;
&lt;dependentAssembly&gt;
&lt;assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls" version="6.0.0.0"
processorArchitecture="X86" publicKeyToken="6595b64144ccf1df"
language="*" /&gt;
&lt;/dependentAssembly&gt;
&lt;/dependency&gt;
&lt;/assembly&gt;
</pre>
 
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">block 相关 api </span>
</strong>
</p>
<p> </p>
<p><span style="color: #0000ff;">rb_yield(VALUE)</span>
最简单,相当于单参数 yield</p>
<p><span style="color: #0000ff;">rb_yield_values(int, ...)</span>
可以指定 yield 参数个数</p>
<p><span style="color: #0000ff;">rb_block_proc()</span>
可以获得当前的 block proc 对象</p>
<p><span style="color: #0000ff;">rb_block_given_p()</span>
测试是否给了 block</p>
<p> </p>
<p><span style="color: #0000ff;">rb_block_call</span>
和<span style="color: #0000ff;"> </span>
<span style="color: #0000ff;">rb_iterate</span>
<span style="color: #0000ff;"> </span>
最变态,函数签名:</p>
<pre name="code" class="cpp">VALUE rb_iterate(VALUE(*)(VALUE),VALUE,VALUE(*)(ANYARGS),VALUE);
VALUE rb_block_call(VALUE,ID,int,VALUE*,VALUE(*)(ANYARGS),VALUE);</pre>
<p> </p>
<p>感悟:每种语言的设计者,都对某种符号或者某些词有特殊的爱…… </p>
<p> </p>
<p> </p>
<p><strong><span style="color: #ff6600; font-size: medium;">关于 font</span>
</strong>
</p>
<p> </p>
<pre name="code" class="cpp">VALUE set_default_font(VALUE self, VALUE font_str, VALUE char_set, VALUE font_sz) {
ghFont = CreateFont(-NUM2INT(font_sz),0,0,0,0,0,0,0,
NUM2INT(char_set), OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, FF_DONTCARE, StringValueCStr(font_str));
return self;
}
...
SendMessage(hButtonStart, WM_SETFONT, ghFont, 0);</pre>
<p>注意字体要和 charset 相搭配,否则不干活。打 gb2312 alt+右 f12 查看 charset 定义。</p>
<p> </p>
<p> </p>
<p>工作成果: <a href="http://code.google.com/p/ruby191ext/downloads/list" title="http://code.google.com/p/ruby191ext/downloads/list">http://code.google.com/p/ruby191ext/downloads/list</a>