#tqrk03 で発表した内容がアレだったので、無限ストリームをrubyでやった

東急Ruby会議(#tqrk03)に遊びに行ったら、@tadasyの罠にハメられて無意味に3分LTすることになった。
なんの準備もしてなかったので、空気を読まずに前の記事に書いたHaskellがすげえっていう話をすることにした。
だってRubyわかんねーんだもん。
んで、みんな酒が入った勢いで笑ってたが何一つ意味分からなかったと思われるので、無限ストリームのやつをRubyに移植した。私はRubyまったくわからないので、なんかおかしな書き方だったら教えてほしい。
プログラムだけ書いて力尽きたので、解説が必要な人はSICPを読んでほしい。

class Stream
	def initialize(car, &cdr)
		@car = car
		@cdr = cdr
	end

	def car
		@car
	end

	def cdr
		@cdr.call
	end

	def take(n)
		(n == 0) ? [] : (cdr.nil?) ? [@car] : cdr.take(n-1).unshift(@car)
	end

	def ref(n)
		(n == 0) ? @car : cdr.nil? ? nil : cdr.ref(n-1)
	end

	def map(&f)
		Stream.new(f.call(@car)) { cdr.map(&f) }
	end
end

class << Stream
	def zipWith(s1, s2, &f)
		car = f.call(s1.car, s2.car)
		new(car) { zipWith(s1.cdr, s2.cdr, &f) }
	end

	def repeat(x)
		new(x) { repeat(x) }
	end

	def integerStartinFrom(n)
		new(n) { integerStartinFrom(n+1) }
	end

	def integer
		integerStartinFrom(1)
	end

	def add(s1, s2)
		zipWith(s1, s2) {|a, b| a + b }
	end

	def mul(s1, s2)
		zipWith(s1, s2) {|a, b| a * b }
	end

	def partialSums(s)
		new(s.car) { add(repeat(s.car), partialSums(s.cdr)) }
	end
end

class Series
end

class << Series
	def integrate(s)
		Stream.zipWith(s, Stream.integer) {|a, b| a / b }
	end

	def exp
		Stream.new(1.0) { integrate(exp) }
	end
	def cos
		Stream.new(1.0) { integrate(sin.map{|a| -a }) }
	end
	def sin
		Stream.new(0.0) { integrate(cos) }
	end
end

def sum(array)
	array.inject(0) {|a, b| a + b }
end

ones = Stream.repeat(1)
integer = Stream.integer

p ones.take(10)
p integer.take(10)
p Stream.add(ones, integer).take(10)
p Stream.mul(integer, integer).take(10)
p Stream.partialSums(integer).take(10)

p Stream.partialSums(Series.exp).ref(10)
p Math.exp(1)
p Stream.partialSums(Series.sin).ref(10)
p Math.sin(1)
p Stream.partialSums(Series.cos).ref(10)
p Math.cos(1)