読者です 読者をやめる 読者になる 読者になる

rescueは継続?

Ruby scheme

2chRubyについて Part 27の135,136,154に対する意見

もう、2週間も前の事に意見するのもあれだけど、自分の頭の中を整理するのもかねて書きます。(※僕は135本人じゃないです。)

たぶん、136、154は「継続=call/cc」と考えているからここで書き込まれている結論に行き着いたんだと思う。その前の129の発言を考えるとどう考えても「継続=call/cc」なんだけどね。135はちがってもっと広く「継続=現在の計算の次の計算」としてとらえていると思う。

継続は現在の計算の次にやることであって、callccだけが継続では無く、継続渡しで渡している無名関数も継続に当てはまる。「プログラミング言語SCHEME」の例題の翻訳だけど、たとえば、このコードのsuccess、failureはそれぞれ成功、失敗時の継続にあたる。

def integer_divide(x,y,success,failure)
   if y == 0
      failure.call("divide by zero")
   else
      success.call(*x.divmod(y))
   end
end

integer_divide(1,1,lambda {|d,m| puts d,m}, lambda {|x| puts x}) # => "1\n0"
integer_divide(1,0,lambda {|d,m| puts d,m}, lambda {|x| puts x}) # => "divide by zero"

次にやること(継続)がきちんと実行されてるでしょ。

で、この継続渡しで考えると、rubyのrescueはbeginの中での計算が失敗したときの失敗継続を渡している。'p e'が、失敗時の継続。

begin
  1/0
rescue => e
  p e
ensure
  p "end"
end

ってことで、継続渡しも考えるとrescueも継続に含まれる。154の発言は129の発言を考えても軽率だと思う。

僕の意見はこれで終わりです。もし違ってたら教えてください。

あと、

schemeでのrubyっぽいbeginを書いたので貼っとく(やりたかったのはこれ)。

(define ruby-raise #f)
(define (div n m)
  (if (= m 0)
      (ruby-raise "divide by zero")
      (/ n m)))
(define (ruby-begin expr rescue ensure)
  (call/cc
   (lambda (succ)
     (rescue (call/cc
              (lambda (raise)
                (succ
                 (fluid-let ((ruby-raise raise))
                   (expr))))))))
  (ensure))
(ruby-begin
 (lambda () (div 1 0))
 (lambda (e) (display e) (newline))
 (lambda () (display "ensure") (newline)))  ; => "divide by zero\nensure\n"
(ruby-begin
 (lambda () (div 1 1))
 (lambda (e) (display e) (newline))
 (lambda () (display "ensure") (newline)))  ; => "ensure\n"