callcc 㨠coroutine 㨠semi-coroutine
Ruby 㧠callcc ã使ã£ã¦ coroutine ã semi-coroutine ãæ¸ãã¦ã¿ã¾ããããã¾ãèããã«è©¦è¡é¯èª¤ã§æ¸ããã®ã§ééã£ã¦ãããããã¾ããããã¨ããããæãã¦ã¿ã¾ãã
coroutine 㯠Modula-2 ã§æ¡ç¨ããã¦ãããã®ãsemi-coroutine 㯠Lua ã§æ¡ç¨ããã¦ãããã® *1 ãå®è£
ããã¤ããã§ãã
callcc 㧠coroutine
ã¾ããµã³ãã«ã以ä¸ã®ã³ã¼ã㯠1 ã3 ã2 ãåºåãã¦çµäºãã¾ãã
c1, c2 = Coroutine.new { p 1; c2.start; p 2 }, Coroutine.new { p 3; c1.start; p 4 } c1.start
$ ruby -rcoroutine test.rb 1 3 2
ããã¤ã¾ãã§è§£èª¬ã
- coroutine.start 㧠coroutine ãèµ·åãã¾ãã
- start ããã¨ãã«å®è¡ãã¦ãã coroutine ã¯æ¢ã¾ãã¾ããä»ã® coroutine ããæ¢ã¾ã£ã coroutine ã start ãããããæå¾ã«æ¢ã¾ã£ãå ´æããåéãã¾ãããµã³ãã«ã§ã¯ãc2.start 㧠c1 ãæ¢ã¾ãããã®å¾ c2 å 㧠c1.start ãããã¨ããc2.start ã®ç´å¾ããå®è¡åéãã¦ãã¾ãã
- ããããã® coroutine ãçµäºããã¨ããã°ã©ã ãã¨çµäºãã¾ãããµã³ãã«ã§ã¯ãp 2 ã®ç´å¾ã§ c1 ãçµäºããã®ã§ããã§ããã°ã©ã çµäºã§ãã
ä»¥ä¸ coroutine ã®ã½ã¼ã¹ã§ããcallcc ã®ç·´ç¿åé¡ã§ãããç°¡åã®ãããã¹ã¬ãããä¾å¤ãªã©ã¯ç¡è¦ã§ãã
class Coroutine @@cur = Coroutine.new attr_accessor :thunk def initialize # æ®ãã®è¨ç®ã¯ããããã¯ãå®è¡ãã¦ããã°ã©ã ãçµäºããã @thunk = proc { yield; exit } end def start callcc do |c| @@cur.thunk = c # æ®ãã®è¨ç®ãæ´æ°ãã @@cur = self # ç¾å¨ã® coroutine ãæ´æ°ãã @thunk.call # ç¾å¨ã® coroutine ãéå§ (ã¾ãã¯åé) ãã end end end
coroutine 㧠semi-coroutine
ã¾ããµã³ãã«ã以ä¸ã®ã³ã¼ã㯠1 ã3 ã2 ã4 ãé ã«åºåãã¦çµäºãã¾ãã
c1, c2 = SemiCoroutine.new { p 1; SemiCoroutine.yield; p 2 }, SemiCoroutine.new { p 3; SemiCoroutine.yield; p 4 } c1.resume #=> 1 c2.resume #=> 3 c1.resume #=> 2 c2.resume #=> 4
$ ruby -rsemicoroutine test.rb 1 3 2 4
ãã¡ããããã¤ã¾ãã§è§£èª¬ã
- semi-coroutine 㯠resume ã§èµ·åãã¾ããsemi-coroutine ã resume ããã¨ãresume ãã semi-coroutine 㨠resume ããã semi-coroutine ã親åã«ãªãã¾ãã
- èªåã®è¦ªãå ç¥ã® semi-coroutine 㯠resume ã§ãã¾ãã (親åé¢ä¿ã¯ãµã¤ã¯ã«ã«ãªããªã) ãä¾ãã°ãc1 ã®ä¸ã§ c2 ã resume ãããã® c2 ã®ä¸ã§ c1 ã resume ãããã¨ã¯ã§ãã¾ããã
- ãã ãç´æ¥ã®è¦ªã ã㯠SemiCoroutine.yield ã¨ããå¥ã®å½ä»¤ã§èµ·åã§ãã¾ãã
- semi-coroutine ãçµäºããã¨ãyield ããã®ã¨åãå¹æã«ãªãã¾ããçµäºãã coroutine ã¯ãã resume ã§ãã¾ããã
è¦ç´ããã¨ãsemi-coroutine 㯠coroutine ã«ããããªå¶éãããããã®ã§ããå¤åã
ã½ã¼ã¹ã¯ãããªæãã
require "coroutine" class SemiCoroutine < Coroutine @@cur = SemiCoroutine.new @@stack = [] private :start def initialize # æ®ãã®è¨ç®ã¯ããããã¯ãå®è¡ã㦠yield ããã @thunk = proc {|*args| yield(*args); @dead = true; SemiCoroutine.yield } end def resume(*args) raise "cannot resume semi-coroutine recursively" if @@stack.include?(self) raise "cannot resume dead semi-coroutine" if @dead @@stack << @@cur # å®è¡ä¸ã® semi-coroutine (= 次ã®è¦ª) ã push start(*args) # åãå¼ã³åºã end def yield(*args) raise "cannot yield non-parent semi-coroutine" unless @@stack.last == self @@stack.pop # 親ãã¹ã¿ãã¯ãã pop start(*args) # 親ãå¼ã³åºã end def SemiCoroutine.yield(*args) @@stack.last.yield(*args) end end
ä¸è¨ã® Coroutine ã使ã£ã¦å®è£
ãã¾ãããresume ã yield ãçµå± start ã§ããéãã®ã¯ã親åé¢ä¿ãããããã¹ã¿ãã¯ã push ããã pop ãããããã¨ãyield ã¯ã¹ã¿ãã¯ã®ããã (ç´æ¥ã®è¦ª) ã«å¯¾ãã¦ããã§ãã¾ãããsemi-coroutine ã coroutine ã«å¶éãããããã®ã ã¨ãããã¨ãè¦ãããããªè¦ããªããããªã
semi-coroutine 㧠coroutine
éã« semi-coroutine 㧠coroutine ãã¨ã³ã³ã¼ããããã¨ãã§ãã¾ã (㨠Coroutine in Lua ã§ä¸»å¼µããã¦ã¾ã) ãå¤åãããªæããstart ã¯ãmaster ã yield ãã¦ãmaster ãã次ã«å®è¡ãããã®ã resume ããããã親åé¢ä¿ã®ã¹ã¿ãã¯ã伸ã³ãªãã®ããã¤ã³ãã§ãã
require "semicoroutine" class Coroutine2 < SemiCoroutine @@master = SemiCoroutine.new do |c, *args| loop { c, *args = c.resume(*args) || exit } end @@first = true def start2(*args) if @@first @@first = false @@master.resume(self, *args) else @@master.yield(self, *args) end end end
c1, c2 = Coroutine2.new { p 1; c2.start2; p 2 }, Coroutine2.new { p 3; c1.start2; p 4 } c1.start2
$ ruby -rcoroutine2 test.rb 1 3 2
ã¾ã¨ã
è¨ããããã¨ã¯ 3 ã¤ã
- coroutine ã使ããªãã®ã¯å¤åééããªãã
- semi-coroutine ã¯çµæ§ãããããããã使ãã ããªãããã§ããªãï¼
- ããããå®é¨ãæ°è»½ã«ã§ãã Ruby ã好ããå¤é¨ã©ã¤ãã©ãªæ±ãã§ããããã callcc æ®ãã¨ãããªãã