Listモナド
文字列を展開するメソッド2つ:
def expander( str, reg1) return [str] unless str =~ reg1 r = [$1,$2,$3] yield(r[1]).inject([]) {|x,y| x << r[0]+y+r[2]} # 複数の展開対象があるかも. # 展開対象が無くなるまで再帰させる? end def expandCharClass(str) expander( str, /(.*)\[([^\]]*)\](.*)/) {|x| x.scan(/./)} end def expandAltWords(str) expander( str, /(.*)\{([^}]*)\}(.*)/) {|x| x.split(/,/)} end p expandCharClass("img[012].jpg") #=> ["img0.jpg", "img1.jpg", "img2.jpg"] p expandAltWords("img.{png,jpg}") #=> ["img.png", "img.jpg"]
をListモナドでくっつける.
class List def List::unit( val ); new([val]); end def List::empty; new([]); end def initialize( val ); @val = val; end def bind( &block ) @val.map(&block).inject([]){|c,a| c+a }.to_list end def to_a; @val; end def empty?(); @val.empty?; end end class Array def to_list; List::new( self); end end p [1,2,3].to_list.to_a #=> [1,2,3] def expandPattern( str) List::unit(str).bind {|x| expandCharClass(x) }.bind {|x| expandAltWords(x) }.to_a end p expandPattern("img[012].{png,jpg}") #=> ["img0.png", "img0.jpg", "img1.png", "img1.jpg", "img2.png", "img2.jpg"]
もしかしてすごいのかも.
オリジナルはArrayを直接弄ってたけど,なんとなく新クラスにしてみた.
(追記 071227:このListは間違ってる気がする.emptyがList::new()でなく,ただのを返せばいい?モナド則的にはおかしいままだけど.)