[#34722] cgi.rb の form の挙動 — FUJIOKA Takeyuki <fujioka@...>

藤岡です。

18 messages 2002/04/02

[#34724] 「たのしい Ruby 」 — Shin-ichiro HARA <sinara@...>

原(信)です。

18 messages 2002/04/02
[#34728] Re: 「たのしい Ruby 」 — matz@... (Yukihiro Matsumoto) 2002/04/02

まつもと ゆきひろです

[#34746] Re: 「たのしい Ruby 」 — TAKAHASHI Masayoshi <maki@...> 2002/04/02

高橋征義です。

[#34752] Re: 「たのしい Ruby 」 — Shin-ichiro HARA <sinara@...> 2002/04/03

原(信)です。

[#34842] [ann] Web 家計簿(β版)リリース — 堀川 久 <vzw00011@...>

こんにちは。

18 messages 2002/04/07
[#34869] Re: [ann] Web 家計簿(β版)リリース — Nobuhide Kanagawa <nobuhide@...> 2002/04/11

こんばんわ!

[#34885] creating a scope / anonymous module — Takaaki Tateishi <ttate@...>

立石です.

38 messages 2002/04/13
[#34891] Re: creating a scope / anonymous module — nobu.nakada@... 2002/04/14

なかだです。

[#34892] Re: creating a scope / anonymous module — Takaaki Tateishi <ttate@...> 2002/04/14

At Sun, 14 Apr 2002 18:00:12 +0900,

[#34894] Re: creating a scope / anonymous module — nobu.nakada@... 2002/04/14

なかだです。

[#34896] Re: creating a scope / anonymous module — Takaaki Tateishi <ttate@...> 2002/04/14

At Sun, 14 Apr 2002 21:08:47 +0900,

[#34899] Re: creating a scope / anonymous module — matz@... (Yukihiro Matsumoto) 2002/04/15

まつもと ゆきひろです

[#34901] Re: creating a scope / anonymous module — Takaaki Tateishi <ttate@...> 2002/04/15

At Mon, 15 Apr 2002 09:51:05 +0900,

[#34902] Re: creating a scope / anonymous module — matz@... (Yukihiro Matsumoto) 2002/04/15

まつもと ゆきひろです

[#34903] Re: creating a scope / anonymous module — Takaaki Tateishi <ttate@...> 2002/04/15

At Mon, 15 Apr 2002 13:53:53 +0900,

[#34904] Re: creating a scope / anonymous module — matz@... (Yukihiro Matsumoto) 2002/04/15

まつもと ゆきひろです

[#34910] Re: creating a scope / anonymous module — Takaaki Tateishi <ttate@...> 2002/04/15

At Mon, 15 Apr 2002 15:07:57 +0900,

[#34958] windows 版 ruby でシステムコマンドが動かない — "jazzski _comp" <jazzski_comp@...>

はじめてrubyを使うのですが、windows版(cygwin版1.6.1)で下記のように

12 messages 2002/04/23

[ruby-list:34943] Thread by callcc

From: Shin-ichiro HARA <sinara@...>
Date: 2002-04-18 09:03:39 UTC
List: ruby-list #34943
原です。

callcc で Thread みたいなものを作る話です。

事の起こりは立石さんが [rubyist:1340] で、もうちょっと Continuation
の応用例で良いのをあげましょう、という話だったんですが、新井さんが、
Continuation なんかいらないんじゃないかと、暴言:-)を吐き、しまいには
まつもとさんも、Rite じゃやめちゃうかも、などと言う始末。一方、Tosh 
さんが、[rubyist:1352] で、choose という Non-deterministic Programming
を実現する非常に興味深い例をあげて、でもちょっとまずいところもあるん
だ、という話でした。

いい加減な要約だなあ。

それはそれとして、と私が下のような遅延評価クラスは、マニュアルに載
せる例としてはいいのではないか、と言ったところ、

-^ lazy-eval.rb
class LazyEvaluation
   def initialize
     if callcc{|@upper| false}
       yield(self)
       self.break
     end
   end

   def call
     if callcc{|@lower| true}
       self.redo
     end
   end

   def break
     @lower.call(false)
   end

   def redo
     @upper.call(true)
   end
end

if $0 == __FILE__
   bye = LazyEvaluation.new{
     puts "Bye"
   }
   puts "Hello"
   bye.call
end
-$ lazy-eval.rb

Tosh さんが、これを元に [rubyist:1370] で、co_fork という形
にしたのでした。次のが私がまたそれを少し拡張したものです。

-^ co-thread.rb
class CoThread
   def initialize
     @threads = []
   end

   def enter
     callcc{|cc| @threads.push(cc); false }
   end

   def exit(x = nil)
     @threads.shift.call(true, x)
   end
   
   def fork
     sw, x = enter
     if sw
       r = yield(x)
       self.exit(r)
     end
     self
   end
   
   def pass(x = nil)
     sw, r = enter
     unless sw
       self.exit(x)
     end
     r
   end
end
-$ co-thread.rb

これによって、Thread とは違い、明示的に次のスレッドに処理を
渡すようなプログラムが書けます。次は 1 から 7 まで、0.5 刻
みで出力する例です。


   require "co-thread"
   ct = CoThread.new
   ct.fork do |x|
     puts x
     puts 2
     puts ct.pass(2.5)
     puts 5
     5.5
   end

   ct.fork do |x|
     puts x
     puts 3
     puts ct.pass(3.5)
     puts 6
     6.5
   end

   puts 1
   puts ct.pass(1.5)
   puts 4
   puts ct.pass(4.5)
   puts 7


前置きが長くなりましたが、この CoThread というのが、かなり良く出来て
いるかもしれない、と思うので説明します。

今までも、callcc を使う話は、カーソルとか [ruby-list:13696]、Queue 
みたいなのとか [ruby-list:13695]、あるいは、平行 each では、MUSHA 
さんの仕事が

   http://www.ruby-lang.org/~knu/cgi-bin/cvsweb.cgi/rough/lib/generator.rb

にあります。

さて、この CoThread を使うと、これらが統一的にまとめられます。
以下にあげるのは、

(1) Proc 互換クラス
(2) 平行 each
(3) 内部イテレータの外部イテレータへの変換
(4) Queue の CoThread 版

で、どれもシンプルで短いものです。


(1) Proc 互換クラス

-^ yaproc.rb
require "co-thread"

class YaProc < CoThread
   def self.new(&b)
     super.fork(&b)
   end

   alias call pass
end

if $0 == __FILE__
   by = YaProc.new{|x| "by" + x }
   puts "Hello"
   puts by.call("e")
end
-$ yaproc.rb


(2) 平行 each

-^ sync-each.rb
require "co-thread"
class SyncEach
   include Enumerable

   def initialize(*es)
     @ct = CoThread.new
     @size = es.first.size
     es.each do |e, i|
       @ct.fork do |a|
	e.each do |x|
	  a.push(x)
	  a = @ct.pass(a)
	end
       end
     end
   end

   def each
     @size.times do
       yield @ct.pass([])
     end
   end
end

if $0 == __FILE__
   foo = SyncEach.new(0..3, 10..13, 20..23)
   foo.each do |a|
     p a
   end
end
-$ sync-each.rb


(3) 内部イテレータの外部イテレータへの変換

-^ generator.rb
require "co-thread"

class Generator
   def initialize(enum, iter = :each, eoi = :eoi)
     @ct = CoThread.new
     @ct.fork do
       enum.send(iter) do |x|
	@ct.pass(x)
       end
       @ct.pass(eoi)
     end
   end

   def next
     @ct.pass
   end
end

if $0 == __FILE__
   g = Generator.new(0..3)

   while :eoi != (x = g.next)
     p x
   end

   puts

   module Fibonacci
     def self.each
       a, b = -1, 1
       loop do
	a, b = b, a + b
	yield b
       end
     end
   end
   
   g = Generator.new(Fibonacci)
   while (x = g.next) < 200
     p x
   end
end
-$ generator.rb


(4) Queue の CoThread 版

-^ co-queue.rb
require "co-thread"

class CoQueue
   def initialize(ct)
     @thread = ct
     @queue = []
   end

   def enq(x)
     @queue.push(x)
     @thread.pass
   end

   def deq
     while @queue.empty?
       @thread.pass
     end
     @queue.shift
   end
end

if $0 == __FILE__
   ct = CoThread.new
   qu = CoQueue.new(ct)

   ct.fork do
     (10..14).each do |x|
       qu.enq(x)
     end
   end

   ct.fork do
     (20..26).each do |x|
       qu.enq(x)
     end
     qu.enq :eoi
   end
   
   while :eoi != (x = qu.deq)
     p x
   end
end
-$ co-queue.rb


それぞれ、Thread を使うとかなり気を使わなければならないところが、
ずいぶん素直に書けていると思います。

CoThread という名前は Cooperating Thread のつもりだけど、もっとい
い名前はないですかね。co-sine とか、co-product などの co- の意味
があると取られてもいけないし。fork, pass もどうかな。


こんな風にライブラリを充実させていけば、callcc も生き延びられる?

In This Thread

Prev Next