豊福@パパイヤです。 けいじゅさん >>チェーン状につながったフィルタオブジェクト >>を通すと合成数はふるい落とされていくというプログ >>ラムです。 > > この題材は, 昔, 本の中で書いた例題(Smalltalkで記述)と基本的に同じもの > だなと懐かしくなりました(^^;;; オブジェクト指向のサンプルプログラムの定番のよう ですね。KL1版と C++版を見たことがあります。今回のは C++版の ruby への焼き直しです。 > # 実は, mathn.rbのために, 同じものをruby版も作ったんですが, あまりにも > # 遅いので, mathn.rb では別のアルゴリズムを採用してしまいました(^^;;; メソッド呼び出しに時間かかるんですかね。 > # 別にオブジェクト指向していませんが, アルゴリズムが面白いと思うので興 > # 味があったら覗いてみて下さい. はい読みました。mathn.rb の class Prime を見て 今回のプログラムを思い出した次第です。 math.rb についてはいくつか質問がありますがそれは また別メールにて。 >> 「こう書いた方が ruby らしい」など教えて下さい。 > > そうですね. まず, Enumeratableをincludeすることを考えると面白いと思い > ます(Sieve#eachを実装する)そうすると, > > primes = Sieve.new(c) > for n in primes > break if n > max > print n, "\n" > end > > などの使い方ができるようになります. > > # ただ, loopは無限に続くので途中で確実に止まることが保証されていないと... > > 数えあげられるもの(Stream系)に関しては, Enumeratableをincludeできるか > まず考えるとよいでしょう. Enumerable を include して each を実装すると 自動的に collect とか find も使えるようになるの ですね。 なるほど勉強になりました。こういうことがサンプル プログラムとともに書いてあるドキュメントがあると いいですね。 > # ただ, loopは無限に続くので途中で確実に止まることが保証されていないと... この後は何が続くのでしょう。 ・「無限ループになったらあきらめろ」 ・「だから確実に止まるように気をつけろ」 ・「だからこれこれの技を使え」 アドバイスを基にしてプログラムを書き直しました。 どうでしょう。 class Stream include Enumerable def each loop do yield out end end end class Counter < Stream def initialize(v) @value = v end def out @value += 1 return @value - 1 end end class Filter < Stream def initialize(src, f) @source = src @factor = f end def out for n in @source if n % @factor != 0 return n end end end end class Sieve < Stream def initialize @source = Counter.new(2) end def out n = @source.out() @source = Filter.new(@source, n) return n end end if ! max = ARGV.shift; max = 100; end max = max.to_i primes = Sieve.new for n in primes if n > max break end print n, "\n" end --- 豊福@パパイヤ unbound / papaya.juice.or.jp toyofuku / juice.or.jp