原です。

In [ruby-math:00879]

>  豊福です。
>
>> ramanujan(proc{|v| v[0]**3 + v[1]**3}).take(2).each do |x|
>>   p x
>> end

>  tail で次の解が見つかってから take(0) が実行されるんですね。
>結局解2個求めるのに解3個生成していたのでした。
>ここにも遅延評価の問題が出てくるのですね。

がーん、もしそうなら、それはバグといってもいいかもしれない。
、、、確かにそうですね。よく指摘していただきました。_o_

対処療法ですが、さしあたってこれで回避できます。

  def take(n)
    if null? or n <= 0
      List(nil)
    elsif n == 1
      List(head){ List(nil) }
    else
      List(head){tail.take(n-1)}
    end
  end

あるいは、

  def take_list(n)
    if n <= 0
      List(nil)
    else
      list = yield
      List(list.head){take_list(n-1){list.tail}}
    end
  end

  take_list(n){ramanujan(proc{|v| v[0]**3 + v[1]**3})}.each do |x|
    p x
  end

とするか、、、


という事はあの SICP(*) も同じ問題を抱えているんじゃないか。もし、

  (define (take s n)
    (if (= n 0)
        '()
        (cons-stream (head s)
              (take (tail s) (- n 1)))))

なんてコードを見つけたら、かの高著にツッコミを入れる事が出来るので
は、、、と思ったのですが、take, take-stream, stream-take なんてもの
は載ってませんでした。さすが。(避けているんだな。)
(*)SICP「計算機プログラムの構造と解釈」(ピアソン)


Haskell ではこういう事がないんですね。これで、Scheme, Ruby に比べて
Haskell の有効性がはっきりしました。Haskell では f(a, b, c) を呼ん
でも a, b, c が遅延評価され、本当に必要になって初めて評価するんです。

Ruby じゃ self を遅延評価させるわけにもいかないですからねえ:-)。も
ちろん、複数の Proc オブジェクトを渡したり、ブロックで条件分岐させ
て、複数のパラメータの遅延評価をエミュレートできますが「いつ実際に
評価させるか」という事に関して場当たり的にならざるを得ない。


ちなみに、全ての自然数をフィルタで振り落とすコードを

  module Main where
  main = print (filter (\x -> False) [1..])

とやってみたら、(もし [] が返ってきたらひっくり返るところでしたが)
さすがの Haskell も無限ループでした。