Topics

・LISPデータ構造の問題点の指摘と抜本的解法としての新プログラミング言語の策定/純粋関数型言語「SPINOZA」

・著書『関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間』 [Day1]たち読み記事 無料公開中

・『関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間』を大変多くの方々にお買い求めいただき、感謝します。
本書の全目次を公開し、質問を受け付けます。


・99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その1】「計算機科学のほんとうの基礎」を理解していない。IQ145のJKと同じ事を語るMITの権威とSICPという聖典の権威を借りてマインドコントロールを解いてみよう

・99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その2】関数型プログラミングのイミュータブルな世界観とイミュータブルな実世界を完全に統合

・10年先を行く斬新な関数型(FRP)データベースについて説明する 99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その3】



・React (.js Facebook)解説 関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間 サポート記事【静的HTML編】
・React 解説【動的HTML-FRP編】
・量子コンピュータが超高速である原理と量子論とそれに至るまでの科学哲学史をゼロからわかりやすく解説01
・量子コンピュータが超高速である原理と量子論とそれに至るまでの科学哲学史をゼロからわかりやすく解説02



・ガラパゴス・ネットスラング=「関数型ポエム」という呪詛、先入観的読書と、フェアなレビューの登場


・『関数型プログラミングに目覚めた!』のレビュー(Day-1)について











2015年8月21日金曜日

加速するJavaScript開発界隈 今、注目を集めるGitHubレポ・ npm ライブラリ 5選

筆者も時折、npmライブラリを公開していますが、

timeengine / Time Engine FRP ( Functional Reactive Programming / 関数型リアクティブ プログラミング) npmライブラリの公開

https://www.npmjs.com/package/timeengine

今、npm(node.js)の公開ライブラリ数が加速的に増加しており、物凄いことになっています。

CodeZine Node.js/JavaScriptの情報収集手段 ~変化が激しいOSSは、直接GitHubをウォッチするより引用

だいたいこのグラフで見ると、1年で2倍になっており、文字通り、指数関数的に増加している様相です。

また、ここ数年、GitHubでホストされているプロジェクトの言語でJavaScriptが1位です。

ここ最近、注目を集めているnpmライブラリ、GitHubに公開されているプロジェクトを示します。

JAWS: The Server-less Stack

https://github.com/jaws-stack/JAWS

今GitHub@JavaScript界隈で一番注目されているプロジェクト。
著書でもちらっと触れた、関数型クラウドサービス、 Amazon Web Services Lambda Functionsを利用したアプリケーションスタック。

JavaScriptで関数型プログラミングやるのがそもそも適していない、などなど一部国内の界隈で眠いことを言う方々を尻目に、Amazonクラウド環境でホストされるJavaScriptの関数のみをコールしてWebアプリケーションのバックエンドを構築するという次世代アプリケーションスタック。

Goals:

  • Use No Servers: Never deal with scaling/deploying/maintaining/monitoring servers again.
  • Isolated Components: The JAWS back-end is comprised entirely of AWS Lambda Functions. You can develop/update/configure each separately without affecting any other part of your application. Your app never goes down… only individual API routes can go down.
  • Scale Infinitely: A back-end comprised of Lambda functions comes with a ton of concurrency and you can easily enable multi-region redundancy.
  • Be Cheap As Possible: Lambda functions run only when they are called, and you only pay for when they are run.

ということで、

とにかくクラウドでもなんでも自サーバーを保持しないので、いろんな面倒から解放される(はず)だ、

とにかく隔離されたコンポーネントだ、関数型のAWSラムダ関数だ、サーバーはないので落ちることはない、

無限にスケールする、マルチリージョンのコンカレントの関数だ、

関数コール分の従量制課金なので、コスパ最強のはずだ、

という、まさに次世代クラウドコンピューティング全開のWebアプリケーションの未来像が提示されています。

個人的には、まだ時期尚早、というか時間が加速しているので、そのうちすぐ検討しなければいけないのかな、という予感もありますが、今のところはAzureクラウドで快適なので、やはり人柱になるには現在の時間スケールで早熟すぎるという印象で、正直まだ面倒臭い感じがします。ただ時流に乗りまくってるビジョナリー、パイオニア達が一定数存在しており、やはり時間が加速している雰囲気をひしひしと感じています。

dragula

http://bevacqua.github.io/dragula/

GoogleKeepみたいな軽快なドラッグUIのライブラリ
ドラッグとドラキュラでドラグラというネーミング。

オフィシャルのReactコンポーネントのブリッジもある。

https://github.com/bevacqua/react-dragula

Reactはすでに業界標準。これは普通に使える。

algebra.js

http://algebra.js.org/
https://github.com/nicolewhite/algebra.js

Build, display, and solve algebraic equations in JavaScript.

代数の方程式を書いたり、LaTeX表示にも対応して表示したり、解くライブラリ。

Mathematicaみたいな大掛かりなものでなく、こういう基本的で簡潔なライブラリは今後何気に重宝しそう、と個人的に思いました。

Professor Frisby’s Mostly Adequate Guide to Functional Programming

https://github.com/DrBoolean/mostly-adequate-guide

JavaScriptの関数型プログラミング教本。

GitHubはもはやコードのプロジェクトだけではなく、書籍(Eブック)の発表の場としても活用されている。

Summary

軽妙な語り口とイラストで内容も非常に濃密で品質が高く必読。

ライセンスは、CC BY-SA 4.0。こんなものがクリエイティブ・コモンズのライセンスででGitHubに無料でポンポンと(すべてのプロジェクトは開発者、筆者が心血を注いだ結晶(自分がそうだからわかる)だが、客観的事象としては加速しすぎていてそのようにしか見えない)UPされている時代になっている。

You Don’t Know JS (book series)

https://github.com/getify/You-Dont-Know-JS
https://www.kickstarter.com/projects/getify/you-dont-know-js-book-series

同じく、GitHubにUPされているCC3-BY-NC-ND ライセンスの無料で読めるJavaScript本。

http://www.amazon.co.jp/You-Dont-Know-JS-Going-ebook/dp/B00V20DQU8

AmazonKindle版でも無料。

先ほどの関数型本もそうだが、他のGitHubプロジェクト同様にIssueがあり、

https://github.com/getify/You-Dont-Know-JS/issues

タイポはもちろん校正が集合知によって為されていくという、出版物とWikiの垣根も曖昧になってきたという趨勢。

すでにここにある未来

とにかく、レイ・カーツワイルの収穫加速の法則でシンギュラリティに向けて邁進する塩梅がどんなものか、一番「身近で手軽に」感じられるのがGitHubのJavaScript関連のレポジトリーやnpmライブラリ界隈だと思います。

2015年8月20日木曜日

timeengine / Time Engine FRP ( Functional Reactive Programming / 関数型リアクティブ プログラミング) npmライブラリの公開

timeengine / Time Engine FRP ( Functional Reactive Programming / 関数型リアクティブ プログラミング) npmライブラリの公開

worldcomponent

worldtimestream

のコンセプトを継承したライブラリです。

https://github.com/kenokabe/timeengine
https://www.npmjs.com/package/timeengine

timeengine

Time Engine is the True Functional Reactive Programming (FRP) Library from the Point of View of Physics, our World and Time

NPM version DownloadsDependency statusDev Dependency statusnpm

NPM

The World, Time, Physics, Mathematics, Equations, and Functional Reactive Programming

JavaScriptで時間発展する物理系=私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証

から再掲/

時間発展する物理系、つまり、私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証をJavaScript言語でしてみましょう。

我々の馴染みの深い「放物線」を例に取ります。
「放物線を描く」と日常的によく使いますが、物理学(日本語)では正確には、「斜方投射」と言います。

斜方投射(しゃほうとうしゃ)とは物体をある初速度をもって空中に投げ出す動作である。空気抵抗が十分小さく無視できる場合、斜方投射された物体の軌跡は放物線を描く

enter image description here

水平方向にx軸、
鉛直上向きにy軸をとります。

初速 
偏角 
のとき、
斜方投射してからの経過時間   における
物体の速度および座標

という恒等式で表せます。(は 重力加速度=9.8 m/ss)

これがニュートン物理学の時間発展する恒等式です。

. タイガー・ウッズの平均ヘッドスピード57.5m/s ボール初速度85.0~86.5m/sと公表されています。

らしいですから、
初速を85.0m/s、偏角30度とし、空気抵抗を無視したゴルフのスーパーショットっぽい斜方投射を上記時間発展する恒等式をそのまま用いて、
timeengine
Reactを利用して関数型リアクティブプログラミングのコードを書くと以下のようになります。

//MKS system of units
var V0 = 85.0; // m/s
var DEG = 30; //degree
var THETA = DEG / 180 * Math.PI; //radian
var G = 9.8; //gravity const

//10msec time resolution
//t seconds elapsed since t0
var t = __.intervalSeq(10).tMap((tt, t0) => (tt - t0) / 1000);

var x = t.tMap((t) => V0 * Math.cos(THETA) * t);

var y = t.tMap((t) => V0 * Math.sin(THETA) * t - G * Math.pow(t, 2));

The full code is represented at the bottom of this document.

Live Demo

http://sakurafunctional.github.io/demo/react-physics/

Basic

The only API you get to know is tMap.

tMap maps a time-sequence to another time-sequence.

Time Engine is all about tMap.

Reactive Programming in JavaScript

var x = __(); // time sequence
var y = x.tMap((x) => x * 2); // y = x * 2

x.t = 3;
console.log(x.t); //3
console.log(y.t); //6

x.t = 5;
console.log(x.t); //5
console.log(y.t); //10

Declarative code like Math equation and Single (no duplicate) update by automatic dependency resolution

var a = __();
var b = __([a]).tMap(([a]) => a * 2); // b.t = 1 * 2 = 2
var c = __([a, b]).tMap(([a, b]) => a + b * 3); // c.t = 1 + 2 * 3 = 7
var d = __([b]).tMap(([b]) => b * 100); // d.t = 2 * 100 = 200
var e = __([a, b, c, d]).tMap(([a, b, c, d]) => a + b + c + d); //210

a.t = 1; // a is updated, and the whole equations will be evaluated.

Atomic update using Promise

var atomic = __([a, b, c, d, e])
  .tMap(([a, b, c, d, e]) => ({
      a,
      b,
      c,
      d,
      e
  }));

var timeseq10 = atomic.tMap((val) => {
  __.t = __.log('atomic', val);
});

Promise

var m = __();
var n = __();
var o = __();
var p = __([m, n, o]).tMap(() => 'Promised');

var timeseq15 = __.timeoutSeq(6000)
  .tMap(() => m.t = 'some');
var timeseq16 = __.timeoutSeq(7000)
  .tMap(() => n.t = 'time');
var timeseq17 = __.timeoutSeq(8000)
  .tMap(() => o.t = 'other');

var timeseq18 = __.timeoutSeq(10000)
  .tMap(() => m.t = 'some');
var timeseq19 = __.timeoutSeq(11000)
  .tMap(() => n.t = 'time');
var timeseq20 = __.timeoutSeq(12000)
  .tMap(() => o.t = 'other');

var timeseq21 = m.tMap((m) => {
  __.t = __.log({
    m
  });
});

var timeseq22 = n.tMap((n) => {
  __.t = __.log({
    n
  });
});

var timeseq23 = o.tMap((o) => {
  __.t = __.log({
    o
  });
});

var timeseq24 = p.tMap((p) => {
  __.t = __.log({
    p
  });
});

Install

node / io.js

$ npm install timeengine

WebBrowser

ES5 native

include

https://github.com/kenokabe/timeengine/blob/master/timeengine.js

then

<script type="text/javascript" src="./timeengine.js"></script>

ES6 with Babel transpiler

https://babeljs.io/

include

https://github.com/kenokabe/timeengine/blob/master/babel-browser.js

https://github.com/kenokabe/timeengine/blob/master/timeengine.jsx

then

<script src="./babel-browser.js"></script>
<script type="text/babel" src="./timeengine.jsx"></script>

Test

$ npm test

equivalent to

$ babel timeengine.jsx -o timeengine.js; babel-node test.jsx

test.jsx

(() => {
  'use strict';

  var __ = require('./timeengine.js');

  __.t = __.log('test.jsx started...');

  //Reactive and Declarative code ===============
  var x = __(); // time sequence
  var y = x.tMap((x) => x * 2); // y = x * 2
  x.t = 3;
  console.log(x.t); //3
  console.log(y.t); //6

  x.t = 5;
  console.log(x.t); //5
  console.log(y.t); //10

  /*
    //comment out, dependency Error occures here
    //since y depends on x, this is an illegal operation

    y.t = 100;
    console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + x.t);
    console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + y.t);
  */

  //store values on timeStamps ==============

  var i = __(true); //store flag = true
  var j = __([i], true).tMap(() => i.t * 2); // j = i * 2

  i.t = 3;
  console.log(j.t); //6

  i.t = 5;
  console.log(j.t); //10

  // seq can be operated just like vanilla JavaScript Array
  __.t = __.log('i.length', i.length);

  i.map((val) => {
    __.t = __.log('i.t', val); // 3, 5
  });

  j.map((val) => {
    __.t = __.log('j.t', val); //6, 10
  });

  var timestamp_i0 = i.TimestampOnIndex(0);
  var timestamp_i1 = i.TimestampOnIndex(1);
  var timestamp_j0 = j.TimestampOnIndex(0);
  var timestamp_j1 = j.TimestampOnIndex(1);

  __.t = __.log(i.T(timestamp_i0)); //3
  __.t = __.log(i.T(timestamp_i1)); //5
  __.t = __.log(j.T(timestamp_j0)); //6
  __.t = __.log(j.T(timestamp_j1)); //10


  //==============================================

  //------------------------
  var timeseq0 = __
    .timeoutSeq(500, true) // store === true
    .tMap((t) => {
      __.t = __.log('--------------------------------------------');
      return t;
    });

  var timeseq1 = timeseq0.tMap((t) => {
    __.t = __.log('timeseq0.t', t);
    __.t = __.log('stored to arrray', timeseq0[0]); // same val
  //stored to the seq array
  });

  var f = (tt, t0) => {
    __.t = __.log('t0', t0);
    __.t = __.log('tt', tt);
  };
  var timeseq2 = __.timeoutSeq(1000).tMap(f);
  var timeseq3 = __.timeoutSeq(2000).tMap(f);

  //------------------------

  var timeseq4 = __.timeoutSeq(2500)
    .tMap(__.log('-------------------------------------------'));

  // Single (no duplicate) update by dependency analysis
  var a = __();
  var b = __([a]).tMap(([a]) => a * 2); // b.t = 1 * 2 = 2
  var c = __([a, b]).tMap(([a, b]) => a + b * 3); // c.t = 1 + 2 * 3 = 7
  var d = __([b]).tMap(([b]) => b * 100); // d.t = 2 * 100 = 200
  var e = __([a, b, c, d]).tMap(([a, b, c, d]) => a + b + c + d); //210

  var timeseq5 = a.tMap((a) => {
    __.t = __.log({
      a
    });
  });

  var timeseq6 = b.tMap((b) => {
    __.t = __.log({
      b
    });
  });

  var timeseq7 = c.tMap((c) => {
    __.t = __.log({
      c
    });
  });

  var timeseq8 = d.tMap((d) => {
    __.t = __.log({
      d
    });
  });

  var timeseq9 = e.tMap((e) => {
    __.t = __.log({
      e
    });
  });

  // Atomic update using build-in Promise mechanism

  var atomic = __([a, b, c, d, e])
    .tMap(([a, b, c, d, e]) => ({
        a,
        b,
        c,
        d,
        e
    }));

  var timeseq10 = atomic.tMap((val) => {
    __.t = __.log('atomic', val);
  });

  var timeseq11 = __.timeoutSeq(3000)
    .tMap(() => a.t = 1);

  var timeseq12 = __.timeoutSeq(3500)
    .tMap(__.log('--------------------------------------------'));


  var timeseq13 = __.timeoutSeq(4500)
    .tMap(() => a.t = 5);

  //---------------------------------------------
  var timeseq14 = __.timeoutSeq(5000)
    .tMap(__.log('--------------------------------------------'));


  //Promise---------------------------------------------

  var m = __();
  var n = __();
  var o = __();
  var p = __([m, n, o]).tMap(() => 'Promised');

  var timeseq15 = __.timeoutSeq(6000)
    .tMap(() => m.t = 'some');
  var timeseq16 = __.timeoutSeq(7000)
    .tMap(() => n.t = 'time');
  var timeseq17 = __.timeoutSeq(8000)
    .tMap(() => o.t = 'other');

  var timeseq18 = __.timeoutSeq(10000)
    .tMap(() => m.t = 'some');
  var timeseq19 = __.timeoutSeq(11000)
    .tMap(() => n.t = 'time');
  var timeseq20 = __.timeoutSeq(12000)
    .tMap(() => o.t = 'other');

  var timeseq21 = m.tMap((m) => {
    __.t = __.log({
      m
    });
  });

  var timeseq22 = n.tMap((n) => {
    __.t = __.log({
      n
    });
  });

  var timeseq23 = o.tMap((o) => {
    __.t = __.log({
      o
    });
  });

  var timeseq24 = p.tMap((p) => {
    __.t = __.log({
      p
    });
  });

  var timeseq25 = __.timeoutSeq(13000)
    .tMap(__.log('--------------------------------------------'));

  var f99 = () => {
    __.t = __.log('Any Event Function can be wrapped.');
  };
  __.t = __.wrap(setTimeout)(f99, 14000);
  //onMousemove or whatever instead of setTimeout

  ///-----------------------------------------------

  var timeseq26 = __.timeoutSeq(15000)
    .tMap(() => {
      __.t = __.log('--------------------------------------------');

      var timeseq27 = __
        .intervalSeq(1000)
        .tMap((tt, t0) => (tt - t0) / 1000)
        .tMap((tt) => {
          __.t = __.log(tt);
          return tt;
        });

    });

})();

result

> babel timeengine.jsx -o timeengine.js; babel-node test.jsx

test.jsx started...
3
6
5
10
6
10
i.length 2
i.t 3
i.t 5
j.t 6
j.t 10
3
5
6
10
--------------------------------------------
timeseq0.t 1440134670777
stored to arrray 1440134670777
t0 1440134670277
tt 1440134671278
t0 1440134670277
tt 1440134672277
-------------------------------------------
{ c: 7 }
{ e: 210 }
atomic { a: 1, b: 2, c: 7, d: 200, e: 210 }
{ d: 200 }
{ b: 2 }
{ a: 1 }
--------------------------------------------
{ c: 35 }
{ e: 1050 }
atomic { a: 5, b: 10, c: 35, d: 1000, e: 1050 }
{ d: 1000 }
{ b: 10 }
{ a: 5 }
--------------------------------------------
{ m: 'some' }
{ n: 'time' }
{ p: 'Promised' }
{ o: 'other' }
{ m: 'some' }
{ n: 'time' }
{ p: 'Promised' }
{ o: 'other' }
--------------------------------------------
Any Event Function can be wrapped.
--------------------------------------------
1.002
2.004
3.006
4.007
5.008

React Physics Test

enter image description here

index.jsx

/*global React __ */

(() => {
  'use strict';
  //MKS system of units
  var V0 = 85.0; // m/s
  var DEG = 30; //degree
  var THETA = DEG / 180 * Math.PI; //radian
  var G = 9.8; //gravity const

  //10msec time resolution
  //t seconds elapsed since t0
  var t = __.intervalSeq(10).tMap((tt, t0) => (tt - t0) / 1000);

  var x = t.tMap((t) => V0 * Math.cos(THETA) * t);

  var y = t.tMap((t) => V0 * Math.sin(THETA) * t - G * Math.pow(t, 2));

  //==============================================================
  var Drawscale = 4; //4 dot = 1 meter

  class ReactComponent extends React.Component {

    constructor() {
      super();
      var timeseq = __([x, y])
        .tMap(([x, y]) => [50 + x * Drawscale, 300 - y * Drawscale])
        .tMap(([x, y]) => {
          this.rx = x;
          this.ry = y;
          this.forceUpdate();
        });
    }

    render() {
      var el = (
      <div>
    <h1>For new shot, Just Reload the browser page</h1>
    <svg height = "100%"  width = "100%">
        <circle r="5" fill="blue"
      cx = {this.rx}
      cy = {this.ry}/>
    </svg>
  </div>
      );
      return el;
    };
  }

  var mount = React.render(<ReactComponent/>, document.body);

})();

Live Demo

http://sakurafunctional.github.io/demo/react-physics/

2015年8月3日月曜日

JavaScriptではES6+とReact-JSXからES5へのトランスパイルが標準に / ATOMエディタで最速環境構築 厳選パッケージ 3 + 3 2015年夏バージョン

【注意】この記事は2015年夏に書かれましたが、事態は極めて流動的であり、この記事の内容はすぐに古くなる可能性があります。

JavaScriptはES6+からのトランスパイル形式が標準になりつつある

これまで、CoffeeScriptやTypeeScriptなどJavaScriptトランスパイル言語がありましたが、標準ではありませんでした。

しかし、FacebookのReactの独自言語JSXや次世代JavaSciptのECMA Sciptバージョン6(ES6/コードネームHarmony)が台頭してくるにつれ、すべてはES6+からレガシーのバニラJavaScript(ES5以下)へ、トランスパイルする形式に統合されつつあります。

Reactのビルドシステムは、トランスパイラBabel(旧6to5)へ移行、JSTransformerなどは廃止の方向

Deprecating JSTransform and react-tools (June 12, 2015)

Today we’re announcing the deprecation of react-tools and JSTransform.

As many people have noticed already, React and React Native have both switched their respective build systems to make use of Babel. This replaced JSTransform, the source transformation tool that we wrote at Facebook. JSTransform has been really good for us over the past several years, however as the JavaScript language continues to evolve, the architecture we used has begun to show its age. We’ve faced maintenance issues and lagged behind implementing new language features. Last year, Babel (previously 6to5) exploded onto the scene, implementing new features at an amazing pace. Since then it has evolved a solid plugin API, and implemented some of our non-standard language features (JSX and Flow type annotations).

react-tools has always been a very thin wrapper around JSTransform. It has served as a great tool for the community to get up and running, but at this point we’re ready to let it go. We won’t ship a new version for v0.14.

Migrating to Babel

Many people in the React and broader JavaScript community have already adopted Babel. It has integrations with a number of tools. Depending on your tool, you’ll want to read up on the instructions.

We’ve been working with the Babel team as we started making use of it and we’re confident that it will be the right tool to use with React.

enter image description here

https://app.codegrid.net/entry/babel-1

次世代デファクト、Facebook-ReactのJSXとES6トランスパイラBabelの親密な関係

上記Facebookのブログで発表されたBabelへビルドシステムを完全移行させる方針、そして、FacebookのReact開発チームがBabel開発チームと協働していることから明らかですが、ES6+トランスパイラであるBabelはJSXを完全にサポートしており、今後React-JSXの「標準」のコンパイラとなります。

ES6へ移行する最大の問題は、巷のブラウザ、そしてnode/io.jsに何時まで経ってもまともにサポートされておらず、実用的な観点から実入りがないというものがありましたが、BabelによってES5以下にトランスパイルされるため、互換性の問題は無くなり、今すぐすべてのES6仕様が利用できることになります。

そして、JSXは今後、ES6+の仕様に準拠し、依存する言語仕様に進化していく方針なので、Babelに適応することで、すべての問題が解決されます。今後JavaScriptのプログラマはBabelのトランスパイルシステムにコーディングを依存していくことになります。

ATOMエディタではどうなのか?

Built-in 6to5 support

Since this post was originally published the 6to5 library was renamed to babel so packages should now use the “use babel”; pragma in their JavaScript files.

ATOMエディタでは、すでにuse babelと指定することによりBabelがBuilt-inされておりES6でのパッケージ開発のサポートがされています。

念の為ですが、これはパッケージ開発のみのようです。つまり、ATOMにはBabelがビルトインされており、ES6+で開発したATOMライブラリはuse babelフラグの指定により、Babel経由でトランスパイル実行されるということなのでしょう。

ATOMエディタですべてのES6開発をシームレスに行うための最速環境構築

そこで、この記事では、ATOMエディタですべてのES6開発をシームレスに行うための最速環境構築を紹介します。

冒頭に書いたとおり事態は流動的なので、パッケージの組み合わせなどより良いものが近い将来登場する可能性は大いにありますが、現時点で筆者が認識しているベストプラクティスです。

再現性を確保したいので、開発環境をゼロからインストールをすることを想定しています。

ちなみに筆者の環境は、Debian8.1です。

基盤

nvm をインストール

https://github.com/creationix/nvm

nvmからio.jsをインストール

nvm install iojs

. ~/.nvm/nvm.sh
nvm use iojs

確認
node -v

ATOMをインストール

https://atom.io/

Terminalの作業

Babelをnpmインストール

http://babeljs.io/

Babel is a JavaScript compiler.
Use next generation JavaScript, today.

..

npm install -g babel

これで、babelコマンドが利用できるようになり、ターミナルで

babel script.js

などとすることにより、ES6やJSXコードをES5にトランスパイルします。

ESLint with babel-eslintをnpmインストール

http://eslint.org/

The pluggable linting utility for JavaScript and JSX

https://github.com/babel/babel-eslint

babel-eslint allows you to lint ALL valid Babel code with the fantastic ESLint.

Babelプロジェクト公式のESLintプラグインです。ちなみに、JSHintやJSLint用プラグインはプロジェクトには存在しません。時代の流れを感じます。
時代はESLint。JSLintでもJSHintでもなくESLint。

babel-eslintのgithubレポページの説明に従って両方インストールします。

npm install -g eslint babel-eslint

.eslintrcというESLint設定ファイルに以下の内容をコピペし、ホームディレクトリ直下に新規作成します。

{
  "parser": "babel-eslint",
  "env": {
        "es6": true,
        "node": true,
        "browser": true
  },
  "rules": {
   "semi": [2, "always"],
   "strict": 1,
   "no-undef" : 2
  }
}

これでターミナルから

eslint test.jsx

など、ES6やJSXコードをLintできます。

この.eslintrc設定は"rules":{}がほぼ空の最低限の設定
(Strictモードの宣言がないとWarning【レベル1】される、セミコロン必須、定義なしエラー【レベル2】)で、
http://eslint.org/docs/rules/

を参照しながら、ルールを追加し磨き上げていきます。

.zshrcなどに追加しておくと便利なエイリアス

alias a="atom ./"

など。
aでターミナルのカレントディレクトリをATOMで開く。
基本、もともとATOMはGUIのファイラー経由でなくターミナルでプロジェクトディレクトリを開くように設計されていると思う。

ATOMを起動

★Look&Feel

好みで設定。

筆者の場合
Settings > Themes

UI Theme

  • Atom Dark
    (デフォルトのOne Darkはタブが見難すぎる)

Syntax Theme

file-iconsパッケージをATOMにインストール

https://github.com/DanBrooker/file-icons

enter image description here

本体にマージすべき必須パッケージ。

minimapパッケージをATOMにインストール

https://atom.io/packages/minimap

本体にマージすべき必須パッケージ。

language-babelパッケージをATOMにインストール

https://atom.io/packages/language-babel

Language grammar for ES2015 Javascript and Facebook React JSX syntax. The color of syntax is determined by the theme in use.

.js,.babel,jsx es6エクステンションのES6やJSXコードのシンタックスのハイライトをしてくれる。これ自体もLint機能が有るが弱い。

本体にマージすべき必須パッケージ。

ここまでで、表示は整いました。
enter image description here

ここから、上記TerminalプログラムをATOMで利用するためのパッケージをインストールします。

★Lint設定

linter & linter-eslintパッケージをATOMにインストール

linter-eslintの設定

  • Global Node Pathに、npm config get prefix で得られるNodeのグローバル・パスをコピペ。

  • Use Global Lintをチェック。

★コードFormat (Beautify)

esformatterパッケージをATOMにインストール

Format On Saveにチェック。

JSXのコードで、
class ReactComponent extends React . Component {
のところだけ、余分なスペースが入るのが気になるが、Lintと実行は問題ない。`

~/.atom/packages/esformatter/.esformatter

esformatter-collapse-objectsプラグイン参照を追加

{
"plugins": [
    "esformatter-jsx",
    "esformatter-collapse-objects"
  ],

確認

最終的に6パッケージがインストールされています。

enter image description here

再起動

ATOMのパッケージ、設定は再起動されないと反映されないものがあるので、再起動して挙動を確認します。

オンタイム・トランスパイルメインの設定

一つのやり方として、ファイルエクステンションをJSXあるいはES6に統一しておく、という方法があるでしょう。

node/io.js

標準のnodeコマンドで、

node app.js

と実行する代わりに、Babelに付属しているbabel-nodeコマンドで、

babel-node app.jsx

と直接オンタイムで実行できます。
https://babeljs.io/docs/usage/cli/

トランスパイルのオーバーヘッドがあるだけで、パフォーマンスのデメリットはありません。

Browser

開発時には、オンタイムでトランスパイルしたほうが便利です。
React-JSXでは、JSX-Transfomerというオンタイムのトランスパイラーが利用できますが、これも廃止の方向に向かっており、同様に、Babelを利用します。

https://babeljs.io/docs/usage/browser/

ドキュメントにあるとおり、

<body>
<script src="node_modules/babel-core/browser.js"></script>

<script type="text/babel">
//your Babel ES6/JSX code
</script>
</body>

とするのですが、一部ES7の機能を使いたい場合などのオプション指定のやり方はわからなかったので、同じページにあるAPIを利用して以下のようにも書けば、{state: 0}などのオプション設定が可能になります。

<body>
  <script src="./babel-browser.js" ></script>
  <script>
   var urls = ["./index.jsx"];
    xhrDoc = new XMLHttpRequest();
    xhrDoc.open('GET', urls[0])
    if (xhrDoc.overrideMimeType)
        xhrDoc.overrideMimeType('text/plain; charset=x-user-defined')
    xhrDoc.onreadystatechange = function() {
        if (this.readyState == 4) {
            if (this.status == 200) {
                var data = this.response; //Here is a string of the text data
                var out = babel.run(data, { stage: 0 });
            }
        }
    }
    xhrDoc.send() //sending the request
  </script>
</body>

プロダクション

開発でないプロダクションでは、特にブラウザではES6+/JSXからES5以下へ、あらかじめオフライン環境でトランスパイルしておいたほうがパフォーマンス的に推奨されます。

この場合は、ターミナルで普通にbabelコマンドでES6+/JSXファイルをトランスパイルする、ということになります。

前回、前々回の記事

nodeのFRP(関数型リアクティブ)ライブラリworldcomponentの後継、worldtimestreamの公開

JavaScriptで時間発展する物理系=私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証

はこのBabelを用いたES6+/JSXのコードで開発しています。

2015年7月31日金曜日

JavaScriptで時間発展する物理系=私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証

時間発展する物理系、つまり、私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証をJavaScript言語でしてみましょう。

我々の馴染みの深い「放物線」を例に取ります。
「放物線を描く」と日常的によく使いますが、物理学(日本語)では正確には、「斜方投射」と言います。

斜方投射(しゃほうとうしゃ)とは物体をある初速度をもって空中に投げ出す動作である。空気抵抗が十分小さく無視できる場合、斜方投射された物体の軌跡は放物線を描く

enter image description here

水平方向にx軸、
鉛直上向きにy軸をとります。

初速 
偏角 
のとき、
斜方投射してからの経過時間   における
物体の速度および座標

という恒等式で表せます。(は 重力加速度=9.8 m/ss)

これがニュートン物理学の時間発展する恒等式です。

. タイガー・ウッズの平均ヘッドスピード57.5m/s ボール初速度85.0~86.5m/sと公表されています。

らしいですから、
初速を85.0m/s、偏角30度とし、空気抵抗を無視したゴルフのスーパーショットっぽい斜方投射を上記時間発展する恒等式をそのまま用いて、
worldtimestream
Reactを利用して関数型リアクティブプログラミングのコードを書くと以下のようになります。

code

恒等式の宣言

worldtimestreamで、物理系の時間tをコードに恒常的にマップするworldengineとして宣言しておきます。

___.world = ___((t) => { // world engine

//===========================================================================

});

その中で、恒等式の初期設定が宣言され、

  var V0 = 85.0; // m/s
  var deg = 30; //degree
  var THETA = deg / 180 * Math.PI; //radian
  var G = 9.8; //gravity const

恒等式そのものがtの時間関数coordinateEquationで宣言されています。

  var coordinateEquation = (t) => {
    var x = V0 * Math.cos(THETA) * t;
    var y = V0 * Math.sin(THETA) * t - G * Math.pow(t, 2);
    return {
      x: x,
      y: y
    };
  };

これで、すべての関係性は記述されていますが、この時間発展する時間関数の恒等式を実際の画面表示をするための「計算」は一切なされていません。

つまり、ここまでは、物理系と物理量コードのストリームとの関係性が100%抽象世界として宣言されただけで、コンピュータのハードウェアでその関係性の具現化、つまりふたたび、そのストリームが具体的な物理系としての画面に反映する「計算」タイミングなどの指示は行われていません。

計算からの画面描写(画面描写も関係式の計算に他ならない)

この「計算」部分を一手に司るのが、ReactコンポーネントReactComponentです。

componentWillMount()において、

        var init = () => {
          var T0 = t();
          var f = () => {
            ___.world = ___coordinate.appear(coordinateEquation((t() - T0) / 1000));
          };
          ___.world = t.computeInterval(f, 10); //calculate 10milsec resolution 
        };
        ___.world = t.computeTimeout(init, 0);

で、___coordinateというストリームを、10ミリセカンドの解像度をもってtの時間関数coordinateEquationで「計算」することを宣言します。

___x={___()} ___y={___()}というReactが描写するコンポーネントのXY座標に相当する、worldtimestreamのストリームとして定義されたプロパティは、___coordinateが「計算」されると、適切な画面座標に投影しながら

        var com = this;
        ___.world = ___coordinate.compute((coordinate) => {
          ___.world = com.props.___x.appear(50 + coordinate.x * Drawscale);
          ___.world = com.props.___y.appear(300 - coordinate.y * Drawscale);
          com.forceUpdate();
        });

コンポーネントを再描画します。

このように、FRPライブラリworldtimestreamとReactを利用することで、簡潔に、
時間発展する物理系、つまり、私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)を実現可能です。

___.world = ___((t) => { // world engine 
  //=========================================================================== 
  //MKS system of units 

  var ___coordinate = ___();

  var V0 = 85.0; // m/s 
  var deg = 30; //degree 
  var THETA = deg / 180 * Math.PI; //radian 
  var G = 9.8; //gravity const 

  var coordinateEquation = (t) => {
    var x = V0 * Math.cos(THETA) * t;
    var y = V0 * Math.sin(THETA) * t - G * Math.pow(t, 2);
    return {
      x: x,
      y: y
    };
  };

  //============================================================== 
  var Drawscale = 4; //4 dot = 1 meter 

  var ReactComponent = React.createClass(
    {
      componentWillMount() {
        var com = this;
        ___.world = ___coordinate.compute((coordinate) => {
          ___.world = com.props.___x.appear(50 + coordinate.x * Drawscale);
          ___.world = com.props.___y.appear(300 - coordinate.y * Drawscale);
          com.forceUpdate();
        });

        var init = () => {
          var T0 = t();
          var f = () => {
            ___.world = ___coordinate.appear(coordinateEquation((t() - T0) / 1000));
          };
          ___.world = t.computeInterval(f, 10); //calculate 10milsec resolution 
        };
        ___.world = t.computeTimeout(init, 0);
      },
      render() {
        var com = this;

        var el = (
        <div>
          <h1>For new shot, Just Reload the browser page</h1>
          <svg height = "100%"  width = "100%">
              <circle r="5" fill="blue"
        cx = {this.props.___x.t()}
        cy = {this.props.___y.t()}/>
          </svg>
        </div>
        );
        return el;
      }
    });

  var mount = React.render(<ReactComponent ___x={___()} ___y={___()} />, document.body);
//============================================================== 
//=========================================================================== 
});


Live Demo

http://sakurafunctional.github.io/demo/react-physics/

2015年7月30日木曜日

nodeのFRP(関数型リアクティブ)ライブラリ`worldcomponent`の後継、`worldtimestream`の公開

nodeのFRP(関数型リアクティブ)ライブラリworldcomponentの後継、worldtimestreamをnpmで公開をしました。

https://www.npmjs.com/package/worldtimestream
https://github.com/kenokabe/worldtimestream

FacebookのJSXで開発テストしており、ライブラリもテストも最終的にバニラJavaScriptへコンパイルしています。

Install

node / io.js

npm install worldtimestream

WebBrowser

https://raw.githubusercontent.com/kenokabe/worldtimestream/master/js/worldtimestream.js

をコピーペースト

Rationale

アイデアは、前回の記事です。

関数型プログラミングと古典物理学の密接な関係

Date.now() はストリームへ透過に参照する時間関数ですが「ユーザの現在時間」が暗黙に引数として渡されているため理解しにくいです。

より物理系と時間という物理量の概念を関数型のコードで明示できるように、FRPライブラリをハックしました。

worldtimestreamは命名したとおり、時間軸上のストリームです。
時間要素に依存しているので、worldtimestreamのストリームは物理量です。

___.world = ___((t) => {
//...........
});

という時間発展の恒等式を宣言することにより、
古典物理学の物理量である時間変数tが得られます。

別に時間変数nowと宣言しても構いませんが、現在時間というのは、なかなか哲学的素養がないと理解しにくい概念であるので、恒等的な値tとして宣言します。

以下、すべて基礎となる上記のスコープ内で記述します。

上記コードにより、

時間発展しているworldtimestreamのストリームの物理系の物理量t

が、↓

時間発展しているユーザが現在実行しているコード

へ恒等的にmapされているので、
t()とすることにより、それぞれの瞬間のユーザは透過にその値を参照できます。

つまりそれが、時間発展している世界のそれぞれの瞬間のユーザにとっての「現在時刻」であるということになります。

たとえば、

 ___.world = ___.log(t());

という恒等式を宣言しておくと、
このコードを意識的に計算するアクションを起こした、すべてのユーザのそれぞれの現在時刻がコンソールへ表示されます。

また、ストリーム___aを宣言しておき、

 var ___a = ___();
  ___.world = ___a.compute(() => {
    ___.world = ___.log(t(), 'a', ___a.t());

  });

と恒等式を宣言しておくと、

時間発展するストリーム___a
「過去」から「未来」方向
あるいは
「未来」から「過去」方向
で変化が生じた瞬間に、ユーザの関与なしに任意のコードを自動計算させることが可能です。

  var f0 = () => {
    ___.world = ___.log('test start');
    ___.world = ___a.appear(0);
  };
  ___.world = t.computeTimeout(f0, 0);

というのは、このコード全体が任意のユーザによって最初に実行された瞬間tにおける、ストリーム___aの値を宣言しています。

 var f = () => {
    ___.world = ___a.appear(___a.t() + 1);

  };

  ___.world = t.computeInterval(f, 1000);

とすることで、そこ瞬間を起点として、ストリームの時間軸上で「未来」方向に1秒間のインターバルの値を宣言しています。

この場合は、ストリーム___aのそのインターバル地点のある時間tにおける値が参照されており、その値に1を加えた値をストリーム___aの未来方向の次の瞬間に現れているという「関係性」を宣言しています。

念の為ですが、ストリーム___aは過去から未来まで時間軸上でイミュータブルで変化しません。ストリーム上に離散する値の関係性が上記コードによって宣言されているだけです。

たとえばこのストリーム___aをオブジェクト参照などで、コピーあるいは「バックアップ」すれば、過去から未来までまったく同じストリームがコピーされます。
つまり、未来方向の任意の時間で、
___aの値がappearされるという宣言があるのならば、まったく同じイミュータブルなストリームである___bもその同時の瞬間に値に「変化」が起こるストリームとして宣言されます。

過去未来の時間軸上で別の運命をもつ別のストリームを作成するには、同様に

var ___b = ___();

というような別個の独立したストリームを宣言します。

もし、この独立したストリーム___bが、
ストリーム___aと関係がある場合は、その都度その関係式を宣言します。

たとえば、
___aのストリーム上のある瞬間の値が、
___bのストリーム上の同一瞬間の値と等しくなり、「未来方向」へはずっとその値のままである、という我々が日常レベルで使う用語としての「値のバックアップ」という関係を宣言したいのであれば、

 ___.world = ___b.appear(a.t());

とすれば簡単に出来ます。

あるいは、

___a___bは、物理量tに依存しない形で、恒等的な関係が存在するとき、

たとえば

___b = ___a x 5
の関係を宣言したい場合は、

  ___.world = ___a.compute((x) => {
    ___.world = ___b.appear(x * 5);
  });

とすれば簡単に宣言できます。

Test

test.jsx

'use strict';

var ___ = require('./worldtimestream.js');

___.world = ___((t) => {

  var ___a = ___();
  var ___b = ___();

  ___.world = ___a.compute(() => {
    ___.world = ___.log(t(), 'a', ___a.t());

  });
  ___.world = ___b.compute(() => {
    ___.world = ___.log(t(), 'b', ___b.t());
  });

  ___.world = ___a.compute((x) => {
    ___.world = ___b.appear(x * 5);
  });

  var f0 = () => {
    ___.world = ___.log('test start');
    ___.world = ___a.appear(0);
  };
  var f = () => {
    ___.world = ___a.appear(___a.t() + 1);
  };

  ___.world = t.computeTimeout(f0, 0);
  ___.world = t.computeInterval(f, 1000);

});

実際に、test.jsxを実行した結果は以下のようになります。

1438234695190 ‘a’ 0
1438234695200 ‘b’ 0
1438234696204 ‘a’ 1
1438234696204 ‘b’ 5
1438234697206 ‘a’ 2
1438234697206 ‘b’ 10
1438234698208 ‘a’ 3
1438234698208 ‘b’ 15
1438234699209 ‘a’ 4
1438234699209 ‘b’ 20
1438234700211 ‘a’ 5
1438234700211 ‘b’ 25
1438234701213 ‘a’ 6
1438234701213 ‘b’ 30
1438234702214 ‘a’ 7
1438234702214 ‘b’ 35
1438234703215 ‘a’ 8
1438234703215 ‘b’ 40

関数型プログラミングと古典物理学の密接な関係

『関数型プログラミングに目覚めた!』のレビュー(Day-1)のコメント欄で計算機科学の基礎としての、プログラミングの「時間」要素、そして「時間」を考えるとは即ち、物理学を考えることである、という重要な論点が確認されています。

JavaScriptのDate.now()をimmutableなストリームと、透過な参照をする関数として考えるとき、誤解されやすいのが、

参照透過性(さんしょうとうかせい、英: Referential transparency)は、計算機言語の概念の一種で、文脈によらず式の値はその構成要素(例えば変数や関数)によってのみ定まるということを言う。 具体的には変数の値は最初に定義した値と常に同じであり、関数は同じ変数を引数として与えられれば同じ値を返すということになる。 当然変数に値を割り当てなおす演算である代入 (Assignment) を行う式は存在しない。 このように参照透過性が成り立っている場合、ある式の値、例えば関数値、変数値についてどこに記憶されている値を参照しているかということは考慮する必要がない、即ち参照について透過的であるといえる。

のうち「文脈によらず」「関数は同じ変数を引数として与えられれば同じ値を返す」という要素だと思います。
@nonstarter氏が感じる「謎」

t1 = Date.now(); (0〜9まで足してコンソールに表示); t2 = Date.now(); console.log(t1 == t2);

t1 = Date.now(); (0〜9まで足してコンソールに表示); t2 = t1; console.log(t1 == t2);
とで結果が異なる、というDate.now()の単純明瞭この上ない「参照不透明性」をどうするつもりなのかはまったく謎のママなわけです。

はまさにこの要素の疑念だと読み解けます。

まず、コメント欄で誰も注意していないので、厳しく注意しておきますと、この@nonstarter氏によるコードは関数型プログラミング、あるいは宣言型プログラミングのコードでもなんでもありません。

関数型・宣言型でない理由は単純で、

t1 = Date.now(); // ① 
<09まで足してコンソールに表示するための処理コード> ; // ②
t2 = Date.now(); // ③

はコードが
ステップ ①
ステップ ②
ステップ ③
というように、上から下へ時間遷移とともに流れ、値はコードの上下関係、時間の前後に依存する、という命令型の発想を前提として書かれている命令型のコードなので、そもそもが「参照不透明性」だとか関数型のコードとしては議論するのは間違いです。
ステップ ①

ステップ ③
では「時間」が違うので、Dateというストリームに参照透明にアクセスする時間関数now()の返り値は異なって当然です。

正しい関数型・宣言型のコードを書くと、

var f = function() {
  console.log(Date.now());
};
var dummy1 = setTimeout(f, 0); //ユーザがコードを実行した瞬間に即時実行
var dummy2 = setTimeout(f, 1000); //ユーザがコードを実行した1秒後に実行

こうなります。コードのロジックがコードの上下関係や、時間の前後関係にまったく依存していないことに注意してください。この「非同期」で宣言型のコードでは、ステップ①②③などありません。

<0〜9まで足してコンソールに表示するための処理コード> ;
を関数型で書くならば、その処理の終了のコールバック関数で書きます。@nonstarter氏が書いたような命令の終了の「同期」を待つような命令型のコードで書いてはいけません。

now()の実引数が空だから、「関数は同じ変数を引数として与えられれば同じ値を返す」事を考えるとおかしい!と思うのも、すでにコメント欄で反論されているとおり、間違った考えです。
now()というのは、その特性を表す字面でも明確ですが、時間関数であって、 値はユーザの現在時間に依存するのです。
数学的には、概念的には、コードに表記されずとも暗黙に、ユーザの現在時間が実引数として渡される関数です。

now()という時間関数が返す値はユーザの現在時間に依存するというのは、

@chimetorch氏が引用したコード
http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_dom

document.getElementById("myDIV").onmousemove = function() {myFunction(event)};

function myFunction(e) {
    var x = e.clientX;
    var y = e.clientY;
    var coor = "Coordinates: (" + x + "," + y + ")";
    document.getElementById("demo").innerHTML = coor;
}

event値はユーザの現在時間に依存するというのと等価ですし、

elmのコード

import Graphics.Element exposing (..)
import Mouse
main : Signal Element
main = Signal.map show countClick
countClick : Signal Int
countClick = Signal.foldp (\clk count -> count + 1) 0 Mouse.clicks

の「シグナル」のインデックス値はユーザの現在時間に依存するのと等価です。

もちろん、上記elmの「シグナル」同様に、JavaScriptのDateストリームをFRP的に拡張して、

var f = function(now){console.log(now);};
var dummy = Date
            .interval(1000) // specifies a 1sec interval between each element
            .map(f);

と書けるようにするのは、大変意義あるハックですが、標準で、

var f = function(){console.log(Date.now());};
var dummy = setInterval(f, 1000);

書くほうが楽です。

私が書いた、worldcomponentも、実用的な観点から、
Date.now()と同様に、now()関数で直接値が参照できるように設計しています。これまで触った数々のFRPライブラリの経験から、この仕様のほうが取り回ししやすいという結論です。

もしくは、

var main = Date.map((now) => {
  //now はユーザの現在時刻
  //ここにすべてのコードを記述していく
});

と暗黙でなく明示的な表記にすれば、関数型のコードとしてより美しいかもしれません。
しかし、これはただ
明示的な構造の中にnowと書くか、
暗黙的な実引数でDate.now()と書くかの違いにすぎません。

いずれにせよ、@nonstarter氏による命令型のコード以外、私が書いたものも含め上記すべての関数型・宣言型のコードは、

  • コードのロジックがコードの上下関係や、時間の前後関係にまったく依存していない

のですが、

  • コードの中の値はユーザの現在時間に依存する

ことに注意してください。

前者と後者の区別がつくプログラマは、関数型プログラミング、計算機科学のほんとうの基礎の素養がきちんとありますが、前者と後者の区別がつかず、関数型でなく命令型のコードを書きながら『単純明瞭この上ない「参照不透明性」』などと発言してしまう人は勉強しなおしたほうがよろしいでしょう。

前者については、命令型でない関数型の基礎なので、特にいまさら説明を加える必要はないと思います。 

後者については、関数型プログラミングで、時間変化する領域に踏み込むことになるので、多少の説明が必要だと思います。

念の為、もう何度も繰り返しているのですが、この部分を説明していのが、
私の著書
関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間
やSICP
99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その1】「計算機科学のほんとうの基礎」を理解していない。IQ145のJKと同じ事を語るMITの権威とSICPという聖典の権威を借りてマインドコントロールを解いてみよう
であるということです。

(後者) コードの中の値はユーザの現在時間に依存する、つまり、関数型プログラミングと古典物理学の密接な関係について解説します。

まず、根本の根本の部分ですが、このように時間の値そのものを取り扱うコードにしても、イベント(シグナル)を使うマウスポインタ、クリックのコードにしても、値は時間変化します。

  • コードの中の値はユーザの現在時間に依存する

時間変化するから、「文脈によって変わる」、だから「参照不透明」なミュータブルと考えるのは間違いです。

  • コードのロジックがコードの上下関係や、時間の前後関係にまったく依存していない

というのが、「文脈によって変わらない」という意味で、「参照透明」であるということです。

私、そしてSICPの著者が関数型プログラミング、計算機科学の基礎と不可分として使う物理学の用語では、時間発展と言うのですが、

時間発展(じかんはってん)とは、時間が進むことで物理系が変化することである。
古典物理学における時間発展とは、物理量の値が時間によって変化することである。

変化しているのは、時間が進むことで変化する我々の世界の「物理系」「物理量」であることを理解してください。

古典物理学にせよ、関数型プログラミングのコードにせよ、それは数学なので、「参照不透明」に値が変化することなどはありえません。

古典物理学で絶対時間tが時間が進む(様に見えている)ことで物理系が変化し、物理量の値が時間発展するからといって、絶対時間tが破壊的代入されている、わけではありませんし、関数型プログラミングにしても全く同様です。

正しい関数型・宣言型のコード

var f = function() {
  console.log(Date.now());
};
var dummy1 = setTimeout(f, 0); //ユーザがコードを実行した瞬間に即時実行
var dummy2 = setTimeout(f, 1000); //ユーザがコードを実行した1秒後に実行

は、時間が進むことで変化する我々の世界という「物理系」において不変(immutable)で、参照透過です。

2015年7月25日土曜日

worldcomponent関数リアクティブプログラミング(FRP)ライブラリの破壊的代入について

拙書の延長で、当ブログにて公開している、関数リアクティブプログラミング(FRP)ライブラリ
worldcomponentについて、拙書をレビューすると称する悪意あるQiita記事、『関数型プログラミングに目覚めた!』のレビュー(Day-1)のコメントで、激しい論争が繰り広げれられており、強い関心を持って読み通しました。

この記事では著者/開発者としての見解を提示します。

worldcomponentがオブジェクトの値の破壊的代入による実装がある、との批判ですが、その通りです。

https://github.com/sakurafunctional/worldcomponent/blob/master/worldcomponent.js

これは、JavaScriptのオブジェクトの値が破壊的代入されたときに、イベントが発生するObject.definePropertiessetの特性を利用して実装されているライブラリです。
このような言語仕様の低層のハックが原理的に関数型であるわけがない

Object.defineProperties(value,
  {
    val: //value.val
    {
      get: function()
      {
        return state;
      },
      set: function(x)
      {
        state = x;
        computingF.map(
          function(f)
          {
            f(x);
          });
        return;
      }
    }
  });

この特性により、オブジェクトの変更をWATCHするためのポーリング実装などは不要で、かなり効率的で無駄のない実用に耐えるFRP機構を実現しています。

すでに当該コメント欄でも複数名の有志により見解が示されていますが、拙書では「ハードウェアモード」の操作として表現もしているとおり、根本的に関数型プログラミングのパラダイムを実現するために、低層のライブラリまで関数型で書く必要性も合理性も一切ありませんし、実際にほとんどのJavaScriptやnode.jsで利用可能な公開されている関数ライブラリはそのライブラリの実装自体(ライブラリのソースコード)は関数型で書かれておらず命令型(もちろん破壊的代入も)で書かれています。worldcomponentもその一つの関数ライブラリで、利用することで関数型のコードが書けます。

Object.definePropertiessetというオブジェクトの値への破壊的代入を「感知」する手法を利用しているので、オブジェクトの参照への破壊的代入をもって実装すると、この機構が機能することはありません。

たとえば、

      appear: function(a) {
        var f1 = function() {
          //  value.val = a; 
          //`Object.defineProperties`の`set`機構に不可欠な「値」の破壊的代入をコメントアウト

          var o = {val: a}; //新規オブジェクトの作成
          value = o; //オブジェクト参照への破壊的代入
        };
        return f1;
      },

とコードを変更すると、Object.definePropertiessetはトリガーされません。つまり、原理的にオブジェクト参照への破壊的代入ではこのライブラリは機能しない設計になっています。

JavaScriptの関数型プログラミングのBestPractice

JavaScriptは基本的に参照の値渡し(参考 JavaScriptはオブジェクトについて参照渡しだなんて、信じない)なので、通常 
= (イコール)
で参照であれ、値であれ、オブジェクトをバックアップをしたと見做すのは危険なので、行うべきではありません。

コメント欄に親切に紹介もされていましたが、このような場合のBestPracticeとしては、これも公開されているundersocrelodashImmutable(全部摂書でも紹介しました)の関数ライブラリのオブジェクトのコピー関数を活用して、言語仕様の詳細をライブラリ実装以下に隠蔽してしまい、非関数型的なパラダイムの議論を回避します。

worldcomponentの利用も関数型のパラダイムにおいて、その実装レベルが問題となることはまったくありません。

また、worldcomponentの実装について、@Lambada氏により、無駄に複雑なスパゲッティ・プログラムなどと繰り返し激しい誹謗中傷が繰り広げられております。

私としましては、Object.definePropertiessetを使ってFRPを効率的に実現するために、無駄がないように極限まで洗練させてコードを公開したつもりですが、すでに@Lambada氏は現段階でworldcomponentの仕様も含めて十二分に精査されたことでしょうから、もちろんObject.definePropertiessetを使わない別の方法でも構わないですし、氏が無駄のない複雑でないコードを提示していただければ助かります。氏のより洗練されたコードで代替した上でnpmのバージョンを上げて公開するつもりなのでよろしくお願いします。

なぜ、関数型プログラミングのコードについて「オブジェクト参照」だとか「状態オブジェクトの再利用」の話を熱弁しているのか??

@Lambada氏による珍妙な主張、オブジェクト参照によるバックアップであるなら、

過去の状態への巻き戻しや状態オブジェクトの再利用等が容易

ということですが、このような事象はありえないこともコメントで指摘されているとおりです。

これまでの議論でも明らかですが、JavaScriptでは、worldcomponentReactのオブジェクト如何に関わらず、対象が何であれ対象の内部実装がわからない限り、自分が何をやったのか知ることはできないので、= (イコール)で何かをバックアップしたとするのは危険で問題が生じるので行うべきではなく、BestPracticeとして、何らかの適切な関数ライブラリを利用するオブジェクトのコピーを明示的に行います。

だいたい、何故この人は、オブジェクト指向の「オブジェクト参照」だとか「状態オブジェクトの再利用」の話を関数型プログラミングのコードで熱弁されているのでしょうか??
パラダイムの違いに無頓着であるからですし、一義的に私のコードのあら探し、誹謗中傷に熱心なだけで、まったく全体の景色が見えていないからですね。

たとえば、ポジションをニュートラルにして冷静にさせるためにLisp言語にでも置き換えてみると、Lispにはコピーする関数もありますが、「オブジェクト参照の破壊的代入が・・・コピーが・・・」などという議論にはならず、単に新たな値に対して、コピーでもmapでも関数を用いてイミュータブルに新規に値を明示的に作成するはずです。

この明示的な操作において、容易も困難も何もありません。
意図をもって明示的にやるか、やらないかの違いしかありません。

最後に FRPにおけるオブジェクトのバックアップというナンセンスについて

表層的な観点からは、

oldvalue(バックアップされたとする古い値)

newvalue(新規に出現する値)

などで、

過去の状態への巻き戻しや状態オブジェクトの再利用

するということを示唆しているのでしょうが、
このnewvalue
「値の破壊的代入」がされているとする、
___totalClicks.now()
と何ら違いはないことは自明です。

また、真に関数型パラダイムの観点からは、
(SICPでも解説されているレベルという意味です
99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その1】「計算機科学のほんとうの基礎」を理解していない。IQ145のJKと同じ事を語るMITの権威とSICPという聖典の権威を借りてマインドコントロールを解いてみよう
___totalClicksというのは、イミュータブルなオブジェクトであり、ミュータブルに耐えず変化しているのは、現実世界の我々が意識している「時間」のほうであり、
この我々が常に意識している「現在時間」には、どの瞬間においても常にnow()で参照透過にイミュータブルな時間軸上の現在時刻のストリームデータにアクセスできる、という設計です。

FRP的設計思想として、現在時間のnow()が、___totalClicksというイミュータブルなオブジェクトの唯一の読み取りインターフェイスであり、「オブジェクト」のバックアップなどすべきではありません。

var ___ = worldcomponent;
var ___totalClicks = ___(0);
___.world = ___totalClicks.appear(42); // ___totalClicksの値を42に設定
var ___totalClicksBak = ___totalClicks; // ___totalClicksの「バックアップ」を保存

のようなコードはFRPのコードではないので、書いてはなりません。

真のFRPライブラリとしてのworldcomponentの設計理念としては、もちろん独立したストリームを別個に宣言しておきます。

var ___ = worldcomponent;
var ___totalClicks = ___(0);
var ___totalClicksBak = ___(___totalClicks.now()); // ___totalClicksの「バックアップ」を保存
___.world = ___totalClicks.appear(42); // ___totalClicksの値を42に設定
//...................

このコードは___totalClicksBakという命名や、「バックアップ」を保存というコメントの言葉遣いが真のFRP的に徹底的に間違っていますが、対比するためにやむを得ずそのように書いています。

もちろん、FRPの個々に定義されたストリームは勝手に相互に干渉しあうことなどありませんから、@Lambada氏による

このように、___totalClicksのほうしか更新していないのに、___totalClicksBakの値まで変わっています。

というGlitchは起こりようがありませんし、そもそもFRPにおいて、ストリームをオブジェクト参照によるバックアップするのが間違いです。

たとえばReactにしても、オブジェクト参照コピーによるバックアップが、設計上、API上全く想定されていないのと同じことです。宣言型のコードに取り組むときバックアップなどという概念はナンセンスです。このブログでイミュータブルな真に関数型のDBを紹介しました。
10年先を行く斬新な関数型(FRP)データベースについて説明する 99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その3】
そこでは、

すべてのタイムスタンプにデータを保持するのではなくて、
「差分」が発生した瞬間のデータのみを保持する。
というアイデアは、結構使えるんですね。
というか、とっくに広く使われています。
GitHubです。
Gitのようなバージョン管理システムは、データの差分のみを記録していきます。

という真のFRPの実現の具体例の片鱗を紐解きましたが、GitHubが瞬間瞬間のバックアップでなく、すべてのタイムスタンプですべての事象をイミュータブルにパイルアップして記録していくシステムであるのはよく知られていることです。

FRP的設計思想として、現在時間のnow()以外に、任意の計算可能な、つまり現在時刻より過去という意味ですが、任意の時刻にアクセスできる読み取り可能なインターフェイスを実装しているのが、拙書の最終章Day5で掲載しているtimecomponentというFRPライブラリであるということになります。

以上のような議論に比較して、

oldvalue(バックアップされたとする古い値)

newvalue(新規に出現する値)

というバックアップというのは、いかに非関数型的発想で命令型パラダイムであるか!という事実に気がつけるか気がつけないかがFRPあるいは関数型パラダイムを真に理解できているか否かの違いです。

FRPの議論をするとき、ある論者が、バックアップというナンセンスで批評を始めた時点で、その論者はFRPのことは何も理解していないと断定して構いません。

もちろん拙書を手間暇かけて読解していただいた読者諸氏におかれましては、上記私の意図するところは哲学的根本レベルで伝わっているものと信じます。

Popular Posts