From: Shin-ichro Hara Date: 1998-12-04T22:01:57+09:00 Subject: [ruby-dev:3742] List() 原です。 [ruby-dev:3724] の List クラスを実用的なもの(本当?)にしてみ ました。 List クラスはオブジェクトのリストを表現していて、仕様は次の通り。 (1)List(a, b, c,...) は List クラスのインスタンスを生成する ここで a, b, c,.. は単なるオブジェクトでも List のインスタ ンスでもよい (2)多重代入 X = Y は X = List(Y) と書いても全く同じである 例: x, y = List(1, 2) # x = 1, y = 1 x, y = List([1, 2]) # x = 1, y = 1 *y = List(1, 2) # y = [1, 2] *y = List([1, 2]) # y = [1, 2] x,*y = List(0, [1, 2]) # x = 0; y = [[1, 2]] (3)その他の list.rb の主なメソッド List#size .. リストの長さ Object#single? .. 単項であるか、長さ1のリストであるとき真 Object#to_array .. 単項あるいはリストを配列にして返す Object#to_object .. 単項あるいは単項リストは単項そのもの、 複項リストは配列を返す -----^ list.rb class List attr :list def initialize(*x); @list = x; end def [](x); @list[x]; end def size; @list.size; end def single?; size == 1; end def to_a if single? @list[0].to_a else @list end end def +(other); List.new(*(@list+other.list)); end def inspect; @list.collect{|x| x.inspect}.join(", "); end end class Object def to_l; List.new(*self); end def single? if is_a?(List) single? else true end end def to_array if is_a?(List) list else Array(self) end end def to_object if is_a?(List) if single? self[0] else list end else self end end end def List(*x) if x.size == 0 nil else list = List.new() x.each do |t| list += if t.is_a? List t else List.new(t) end end list end end -----$ list.rb 使用例としては、yield のパラメータとして明示的に複数個を返したい時 yield List(a, b, c,..) として使う。このときブロックパラメータの方 は、|x| で受ければ x.size? でパラメータの数が分かり、与えられた全て は x.to_array で得られ、 x = x.to_object で yield(a, b, c,..) を |x| で受けたのと同じになる。また、|x, y|, |*x| など多重代入的な受け方を した場合は、yield(a, b, c,..) と変わりがない。 リストが与えられる可能性のあるブロックパラメータ |x| に対しては、 to_object などを使って、単項 a が与えられても単項リスト List(a) が与えられても同じ動作をするようにプログラムを作った方が便利であ る。(下の collect の様に) 具体的な使用例 ... Enumerable#each_with_index を次のように変更する。 module Enumerable def each_with_index(&block) i = 0 each { |x| block.call(List(x, i).to_object) i += 1 } end def collect(&block) ary = [] each { |x| ary.push block.call(x.to_object) } ary end end この様にしても、現在の each_with_index の動作に全く変更は ない。(collect も。) {1=>2, 3=>4}.each_with_index {|x| p x} #=> [[1, 2], 0] #=> [[3, 4], 1] また、次の様に each を再定義しても動作は同じである。 class Hash alias _each each def each; _each{|x,y| yield([x,y])}; end end しかし、 class Hash def each; _each{|x,y| yield List(x,y)}; end end {1=>2, 3=>4}.each_with_index {|x| p x} #=> [1, 2, 0] #=> [3, 4, 1] の様に動作の事なる each_with_index を誘導する each の定義も 可能になっている。(ここでの collect はこの each の変更を吸 収するような再定義の例である。) というわけですが、さて(*x = [1, 2] の話はまたちょっと別だけ ども)、この List() が出来たからもう yield の変更は必要ない か、こんな面倒なものを作るなら yield を変更した方がましか、、 どっちでしょう?:-)