ちょー簡略版unlambda
このところSKIコンビネータで遊んでいたのですが、そういえばSKIコンビネータをベースとしたunlambdaって関数型言語があったなぁ思い出しました。ということでちょー簡略版のunlambdaを実装してみました。組込み関数は.x、r、i、k、sのみ実装しています。
require 'stringio' def nlambda(n = -1, xs = [], &f) n = f.arity if n < 0 if n == 0 f[*xs] else lambda {|x| nlambda(n - 1, xs + [x], &f) } end end FUNC_TBL = Hash.new {|h, c| c.chr.to_sym } FUNC_TBL[?.] = nlambda {|x, y | putc x; y } FUNC_TBL[?r] = nlambda {|x | puts; x } FUNC_TBL[?i] = nlambda {|x | x } FUNC_TBL[?k] = nlambda {|x, y | x } FUNC_TBL[?s] = nlambda {|x, y, z| x[z][y[z]] } def evaluate(src) src = StringIO.new(src.to_s) unless src.respond_to?(:getc) c = src.getc case c when ?` then evaluate(src)[evaluate(src)] when ?. then FUNC_TBL[c][src.getc] else FUNC_TBL[c] end end # Hello, world!プログラム p evaluate('`r`````````````.H.e.l.l.o.,. .w.o.r.l.d.!.a') # => Hello, world! # #<Proc:0x02b37570@unlambda.rb:11> # SKK = Iの例 p evaluate('```skkA') # => :A p evaluate('`iA') # => :A p evaluate('```skkA') == evaluate('`iA') # => true # フィボナッチ数の数だけ「*」を表示するプログラム p evaluate('```s``s``sii`ki`k.*``s``s`ks``s`k`s`ks``s``s`ks``s`k`s`kr``s`k`sikk`k``s`ksk') # => # * # * # ** # *** # ***** # ******** # ************* # ********************* # ********************************** # ******************************************************* # ...
おお。意外と短かく綺麗にまとまりました。しかしオリジナルのunlambdaは遅延評価とかcallccの組込み関数もあるのか。やるなー。
参照: http://hw001.gate01.com/eggplant/tcf/unlambda/