From: Christian Neukirchen Date: 2005-12-18T00:41:59+09:00 Subject: Re: multiple blocks (unfold) mental@rydia.net writes: > I've been pondering how to write an "unfold" in Ruby lately, and > I've not really found any non-awkward ways to do it yet. C'mon, let's do complete hylomorphisms. :-) class Hylo class << self alias_method :taking, :new end def initialize(start) @start = start # Useful defaults. @final = lambda { |x| x.nil? } @map = lambda { |x| x } @init = [] @each = lambda { |a, e| a << e } @step = lambda { |x| raise ArgumentError, "No do block given." } end def do(&block); @step = block; self; end def till(&block); @final = block; self; end def collecting(&block); @map = block; self; end def injecting(init, &block); @init, @each = init, (block||@each); self; end def to_a v = @start r = @init until @final[v] r = @each[r, @map[v]] v = @step[v] end r end end def evens(n) Hylo.new(0). do { |x| x + 2 }. till { |x| x >= n }. to_a end def fact(n) Hylo.taking(n). do { |x| x - 1 }. till { |x| x <= 1 }. injecting(1) { |a, e| a * e }.to_a end def tobin(n) Hylo.new(n). do { |x| x / 2 }. till { |x| x <= 0 }. collecting { |x| (x % 2).to_s }. injecting('').to_a end def expand(n) Hylo.new(n). do { |x| x[1..-1] }. till { |x| x.empty? }. collecting { |x| x.first[0] * x.first[1] }. injecting('').to_a end p evens(20) p fact(7) p tobin(42) p expand([['a', 6], ['b', 4], ['c', 2]]) > -mental -- Christian Neukirchen http://chneukirchen.org