javascriptでstream
sicpの中にstreamというデータ構造が出てきます。
streamを使うと無限の長さのデータを表せるらしいです。
でも、streamが分かっているのか分かっていないのかよく分かりません><。
他の言語でstreamのようなものが実装できたら、分かっているということにしようと想います。
注意
- javascriptの使い方が正しいか自信がないです。(特にthisの部分とか)
- あと、call by need ではなく、 call by nameになっていると想います。
- ここに書いてあることの正しさは保証できません
Streamの作成
//Streamのconstructor function Stream(hd,tl){ this.hd = hd; this.tl = tl; //tlは関数 //this.display = function(){print("hd=",this.hd," tl=",this.tl)}; } //アクセスはhdとtlを通してできる。 //Streamのn番目の要素を表示する。 function stream_ref(s,n){ if (n == 0) { return s.hd } else { return stream_ref(s.tl(), n-1); } } //0からn番目までの要素を配列にして返す function stream_to_list(s, n){ var re = [] for(var i=0;i<n;i++){ re[i] = s.hd; s = s.tl(); } return re }
とりあえず実験
自然数のStreamを作成して、表示してみる。
//fromで与えた値から始まる自然数のStreamを返す。 function integer_stream_from(from){ return new Stream(from,function(){return new Stream(this.hd+1,this.tl)}) } var s = integer_stream_from(1); print(stream_ref(s,100)) // 101 print(stream_to_list(s,5)); // 1,2,3,4,5
一応、動いているみたいです。
Streamに操作を加えてみる。
filter関数を定義してみます。
//条件式に合った値のみからなるStreamを返す。 function stream_filter(p,s){ if (p(s.hd)){ return new Stream(s.hd, function(){return stream_filter(p, s.tl())}) } else{ return stream_filter(p, s.tl()) } } //実験 var nums = integer_stream_from(2); //2から始まってる var s = stream_filter(function(e){return e%2==0}, nums); print(stream_ref(s,5)) // 12 //[2,4,6,8,10,12]だから合っている var ss = stream_filter(function(e){return e>100},s); //100より小さい値は存在を消す(ssのStream的に) print(stream_to_list(ss,5)); // 102,104,106,108,110
組み合わせて素数だけからなるStreamを作ってみる。
エラトステネトスの篩というものが作れる。
エラトステネトスの篩自体はこんな感じのアルゴリズムです。
function f(n){ var a = []; var re = []; for(var i =2; i<n; i++){ a[i] = i; } while (a.length!=0){ var x = a.shift(); var a = a.filter(function(e){return e%x!=0}); re.push(x); } return re; } print(f(100)); // ,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
Streamを使った場合
//篩 function sieve(s){ var nextf = function(){ return sieve(stream_filter(function(e){return e%s.hd!=0}, s)) } return new Stream(s.hd,nextf); } //実験 var nums = integer_stream_from(2); print(stream_to_list(sieve(nums), 7)); // 2,3,5,7,11,13,17 print(stream_ref(sieve(nums),100)); // 547
一応動いてます。(でもとても遅いです><)
もっと正しい内容が知りたかったら、SICPを読んだりすると良いかもしれません。