エラトステネスのふるい on JavaScript-1.7/1.8

「エラトステネスのふるい」は、平行プログラミングの基礎的な例としても用いられる。この場合は、各ふるい(sieve)は最初に受け取ったものを素数とし、その担当の素数の倍数を受け取ったらふるい落とし、そうでないものを受け取ったら次のふるいへ渡すコードになる。そして各ふるいがactorとして自律する。このふるいをJS1.7以降のgeneratorで記述している。

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <script type="text/javascript;version=1.8">//<![CDATA[
    // Sieve of Eratosthenes
    var sieve = function sieve(callback) {
      let prime = yield;
      if (prime === null) return;
      callback(prime);
      let succ = sieve(callback);
      succ.next();
      for (let m = yield; m !== null; m = yield) {
        if (m % prime !== 0) succ.send(m);
      }
      succ.send(null);
    };
    
    var doRun = function doRun(maxnum) {
      let writeTo = function (n) {
        document.getElementById("output").innerHTML += n + "<br/>";
      };
      let s = sieve(writeTo);
      s.next();
      for (let i = 2; i < maxnum; i += 1) {
        s.send(i);
      }
      try {
        s.send(null);
      } catch (ex) {}
    };
  //]]></script>
</head>
<body>
  <button type="button" onclick="doRun(100)">run to 100</button>
  <div id="output"></div>
</body>
</html>

*1


参考のために、Haskellとかでよく見かけるタイプの遅延リスト式実装のcomprehension版もあげておく。この実装ではふるい(sieve)は、リストの先頭を素数とし、残りをその素数で割り切れないものだけで(遅延)リストつくって次のふるいに渡し、その結果を最初の素数につなげたリストを返す。

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <script type="text/javascript;version=1.8">//<![CDATA[
    // Sieve of Eratosthenes
    // sieve (prime:gtor) = prime:(sieve [i | i <- gtor, i `mod` prime /= 0])
    var sieve = function (gtor) {
      let prime = gtor.next();
      yield prime;
      let sievedGtor = (i for (i in gtor) if (i % prime !== 0));
      for (let p in sieve(sievedGtor)) yield p;
    };
    var range = function (s, e) {
      for (let i = s; i < e; i += 1) yield i;
    };
    
    var doRun = function doRun(maxnum) {
      let writeTo = function (n) {
        document.getElementById("output").innerHTML += n + "<br/>";
      };
      for (let p in sieve(range(2, 100))) writeTo(p);
    };
  //]]></script>
</head>
<body>
  <button type="button" onclick="doRun(100)">run to 100</button>
  <div id="output"></div>
</body>
</html>

(スーパーpre記法のスクリプト入りhtmlはCDATAをつかったxhtmlで書けばいいっぽい)

*1:Pythonにはない記法なので、for項でyield式を使うのは少し違和感があるけど、ループ内でbreakするのに比べてフィットするのは意外かもしれない