From: "正木 功" Date: 2001-02-27T12:17:33+09:00 Subject: [ruby-list:28333] Re: argument to instance_eval block(Re: 正木です。 DP.様、 青木峰郎様 回答有難うございます。 In mail "[ruby-list:28268] Re: Bignum にBug?" "Minero Aoki" wrote: |が実行されて n = self; x = nil になります。ようするに、二重に |proc を使うと外側のブロックに引数を渡しても内側のブロックには |関係ないというところが意図と違う原因でしょう。 これが知りたかったことです。といってもこういう風になっているとは 全く予想外でした。当然引数は渡されるものと、思い込んでいました。 こういう仕様なら instance_eval を使うことは諦めざるを得ません。 何をやりたいのかの真意が伝わっていないみたいなのでもう一度説明します。 少し長くなりますが御容赦ください。 次のような script (これは "Ruby プログラミング入門" p202 の fib2.rb を見て こんな便利な方法があるのかと思って一般化してみたものです。 演算子や sum,limit 等を定義しておけば、無限数列や無限級数を自然に扱 うことができて非常に便利です。) test.rb -------------------- $mod=ARGV.shift.to_i m=ARGV.shift.to_i class Sequence def initialize(list,*x) @list=list @x=x case $mod when 0 @proc=proc{instance_eval(&proc)} when 1 @proc=eval("proc{"+yield+"}") when 2 @proc=eval("proc",binding) when 3 @proc=eval("proc{"+block_string+"}") end end def [](n) case $mod when 0,1,3 @list[n] || @list[n]=@proc.call(n,*@x) when 2 @list[n] || @list[n]=@proc.call(n,self,*@x) end end def each(n=0,m=nil) if not m i=n loop do yield(self[i]) i+=1 end else (n..m).each{|i| yield(self[i])} end end def find(n=0,m=nil) if m list(n,m).find{|k| yield k} else @list.find{|k| yield k} || (r=nil;each{|x| if yield(x) then r=x;break;end};r) end end def +(y) case $mod when 1 x=self Sequence.new([],x,y){"|n,x,y| x[n]+y[n]"} end end # def *(y) 等 省略 end def (Power={}).[](x) case $mod when 0,3 super || Power[x]=Sequence.new([1],x){|n,x| x*self[n-1]} when 1 super || Power[x]=Sequence.new([1],x){"|n,x| x*self[n-1]"} when 2 super || Power[x]=Sequence.new([1],x){|n,s,x| x*s[n-1]} end end p Power[2].find{|x| x > m} case $mod when 0,3 Prime =Sequence.new([2,3]){|n| (m=self[n-1]+2;m += 2 while self.find{|k| break if k*k>m; m % k == 0};m)} when 1 Prime =Sequence.new([2,3]){"|n| (m=self[n-1]+2;m += 2 while self.find{|k| brea k if k*k>m; m % k == 0};m)"} when 2 Prime =Sequence.new([2,3]){|n,s| (m=s[n-1]+2;m += 2 while s.find{|k| break if k*k>m; m % k == 0};m)} end #print m,"以下の素数\n" Prime.each{|x| break if x > m;p x} ---------------------------------- を $mod=1 として動かすと期待通りの結果になりますが、 $mod=2 は @proc 中では selfを使わないという方法で self の違いの問題を 回避してみた方法ですが、やはり @proc の context の違いのため(この場合 の binding は無意味だったようです )うまくいきません。m>2 だと止まらな くなります。(勿論最後の行で m や n を使わなければ大丈夫ですが。) $mod=0 の時は error になります。これは @proc の書き方がまづいのだろう と思って、どう書いたらうまくいきますか? と言うのが最初の質問の趣旨 だったわけです。 instance_eval の仕様が上の通りならどう書いてもうまくいかないのは当然です。 $mod=3 の時は block の文字列を返す block_string という method が無い限り 当然 error になります。 block の文字列を返す method があればという質問にどなたからも回答がないと いうことは、これは原理的に無理ということみたいですね。 ただ私としては $mod=0 の場合の書き方が一番すっきりしていると思うので 将来 instance_eval の仕様が変更されてこれが可能になった時のことを考えて 、書き換えがやさしそうな $mod 1 を使うことにします。 (本当は文字列で渡すのなら block を使う必要は全くないんですが。) In message "[ruby-list:28277] Re: argument to instance_eval block" on 01/02/26, matz@zetabits.com writes: |selfをすげかえて、かつ引数を渡す方法が現状ではないので、それ |は少々魅力的に感じるのですが、その場合には instance_eval で |はない別の名前が必要だよなあ、というところで止まってます。 これが実現すれば問題は解決します。よろしくお願いします。