豊福@パパイヤです。

けいじゅさん
>>チェーン状につながったフィルタオブジェクト
>>を通すと合成数はふるい落とされていくというプログ
>>ラムです。
> 
> この題材は, 昔, 本の中で書いた例題(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