Ruby標準ライブラリを使って]のライブラリ実装をサボりまくりな話
私がRubyで書いているLisp方言、 [Nendo]の開発状況続き。
RubyでLisp処理系を作ると楽できる
例えば、sort関数。 仕様は『引数にリストを取って、ソート済みの新しいリストを返す』というもの。
nendoが動いている様子。
$ ./nendo
nendo> (sort '(1 5 6 3 4))
(1 3 4 5 6 )
Rubyでは
$ irb
>> *1, 5, 6, 3, 4*.sort
=> *1, 3, 4, 5, 6*
さて、nendoの実装はというと
def getIFunc( name )
case name
.
略
.
when 'sort'
lambda {|arg| arg.to_arr.sort.to_list }
.
略
.
end
end
となっている。 引数argはconsセル用の ‘Cellクラス’ の連結リストで、一旦RubyのArrayに変換することでRuby標準のsort関数を使っている。
上の様に短く書けるのはCellクラスにイテレータを実装したことと、Arrayクラスにto_listメソッドを追加したため。 Cellクラスのキモの部分
class Cell
include Enumerable
def initialize( car = Nil.new, cdr = Nil.new )
@car = car
@cdr = cdr
end
attr_accessor :car, :cdr
.
略
.
def each # Supporting iterator
it = self
while Nil != it.class
yield it
it = it.cdr
end
end
def to_arr
self.map {|x| x.car}
end
end
こちらは、動的にArrayクラスにto_listを追加するコード
class Array
def to_list
cells = self.map { |x|
Cell.new( x )
}
ptr = cells.pop
cells.reverse.each { |x|
x.cdr = ptr
ptr = x
}
return ptr
end
end
sortだけでなくreverseとuniqも同じ
一旦Arrayに変換するだけで良い関数はsortと同様に書ける
def getIFunc( name )
case name
.
.
when 'sort'
lambda {|arg| arg.to_arr.sort.to_list }
when 'reverse'
lambda {|arg| arg.to_arr.reverse.to_list }
when 'uniq'
lambda {|arg| arg.to_arr.uniq.to_list }
.
.
end
end
sortに評価関数を指定したい場合は?
ウーン… どうしようかな… うまくこの仕組みにのっかって行けるかどうか微妙。 その時はsort関数をnendoで実装しなおさないといけないなぁ。 reverseはそのままでいいかも。