lispとrubyとpythonと その7 継続とFiber(rubyと少しだけlisp)
頭が継続脳になっていないためかもしれないけど、継続欲しいなー、、、と普段思うことはない。
でもまぁ継続があるのもrubyの特徴なのかなぁ、と思ったので書いてみる。
簡単な例。
require 'continuation' i = 0 c1 = nil callcc do|c| c1 = c end i = i + 1 printf "counter %s\n",i c1.call if i < 3 #->counter 1 # counter 2 # counter 3 #=>true
はじめて継続をさわった時はなくなったはずのスタックが復活するのにビビッたもんだ。
require 'continuation' $c1 = nil def test0(arg) printf "test0 begin %s\n" ,arg test1 arg printf "test0 end %s\n" ,arg end def test1(arg) printf "\ttest1 begin %s\n" ,arg test2 arg printf "\ttest1 end %s\n" ,arg end def test2(arg) printf "\t\ttest2 begin %s\n" ,arg callcc do |c| $c1 = c end printf "\t\ttest2 end %s\n" ,arg end printf "call test0\n" flg = nil test0 "test" if !flg flg = !flg printf "call c1\n" $c1.call end call test0 #->test0 begin test # test1 begin test # test2 begin test # test2 end test # test1 end test # test0 end test call c1 #-> test2 end test # test1 end test # test0 end test
ついでに1.9から入ったFiberも載せとく。
f = Fiber.new do i = 0 while(true) Fiber.yield i i = i + 1 end end puts f.resume #=>0 puts f.resume #=>1 puts f.resume #=>2
common lispにも限定的だけど継続はある。
例えばcl-cont。
スマートで簡単な使い方の例が思いつかないから以下のコードはかなり適当
(require 'cl-interpol) (cl-interpol:enable-interpol-syntax) (require 'cl-cont) (defvar *cont*) (defun p (a) (format t "test ~A ~%" a)) (cl-cont:with-call/cc (p (cl-cont:call/cc #'(lambda (k) (setf *cont* k) (funcall k 0))))) (funcall *cont* 1) (funcall *cont* 2) (funcall *cont* 3) #->test 0 # test 1 # test 2 # test 3 ;;http://common-lisp.net/project/cl-cont/ ;;にも書いてるけどcall/ccよりはlet/ccを使った方がいい(楽) (cl-cont:with-call/cc (p (cl-cont:let/cc k (setf *cont* k) (funcall k 0)))) (funcall *cont* 1) (funcall *cont* 2) (funcall *cont* 3) #->test 0 # test 1 # test 2 # test 3 (cl-cont:defun/cc f0 (arg) (p (cl-cont:let/cc k (setf *cont* k) (funcall k arg)))) (f0 0) (funcall *cont* 1) (funcall *cont* 2) (funcall *cont* 3) #->test 0 # test 1 # test 2 # test 3 (funcall (cl-cont:lambda/cc (arg) (p (cl-cont:let/cc k (setf *cont* k) (funcall k arg)))) 0) (funcall *cont* 1) (funcall *cont* 2) (funcall *cont* 3) #->test 0 # test 1 # test 2 # test 3