javascriptに足りないもの と 圏論
初めての投稿になります。
お手柔らかに接していただけると幸いです。
なお、記事に対する意見は諸々あると思いますが、間違いなどの指摘をいただければとも思います。
訂正については、指摘に基づいて行いたいと思います。
さて、プロフィールにも書いた通りですが
個人的にwebRTCの1対1接続を作り、そのイベントを拾ってその変化をDOMに反映させるときにオブジェクト指向の限界を知ることになり、関数型プログラミングのために必要な拡張を模索するjavascript難民が私です。 ただ、一般の関数型プログラミングのスタイルを提示するjavascript Ninjaの方々とは少し異色なことをしています。
もちろん私は、javascriptに足りないものを考えているので、プログラムは自然と
Object.definePropertiesによるプロトタイプ拡張を前提としています。
圏論に対する誤解
圏論は難しい
この誤解を生んでいるのは専門的な論理学者や圏論に携わる人々のせいだと思っています。
つまり、圏論に携わる人々は、圏論の用語を使わなければ会話が出来ないのです。
しかし、圏論の用語を使わずとも、簡単な会話が出来る方法があります。
重要なのは像(具体的な値)ではなく、矢印とその意味
あなたが関数型プログラミングするときに重要なのは、3種類の矢印を区別しているか?
ということです。
3本の矢と3つの観点
矢印は3つの意味を持ちます。
- 射 (像:実際の値を対象とする)
- 関手 (圏:像の集合(要素が一つの場合や空の場合もある)を対象とする)
- 自然変換 (関手の集合(たとえ関手が一つでも)一つの圏と考えたものを対象とする)
自分が関数を定義したときに、上記のどの規模で利用しているかが重要だといえます。
矢印とその意味のほうが、実際の値(像またはその集合である圏)よりも重要だという例示になりますが。
「自然数 b が a で割り切れる」ことを射 a → b と定めても圏ができる。
引用:物理学者のための圏論入門
圏論をうまく理解できない人は、数学が結果主義の産物であると考えがちだとも思います。
関数型プログラミングが分からない人にとって、nullは奇異なものとして考えられるでしょう。
しかしながら、自己関手(自分を再定義できる向きの矢印を持つ関数のこと) 「2で割り切れるなら商、でなければ null」という関手(2.に説明した矢印)はmayBeモナド(ここで言うモナドは、正確にはクライスリ圏と呼ばれる圏の一種です。)を定義するのです。
javascript上では…?
全てがオブジェクト。
実はjavascriptも同じはずです。その証拠に、null と undefined 以外はconstructorを持ち合わせています。
つまり全ての有効値は、Object.prototypeを継承しており、オブジェクトです。
(かなり乱暴な言い方ですが…)
では、Object.prototypeを拡張して関数型プログラミングに対応するのは悪いことでしょうか?
いえ、私は必要なことだと感じています。
わざわざ配列に入れて関数型する?
既に値も関数もオブジェクトとして扱われています。
そして、関手、モナドなどは、型クラスとして定義できるものなので、つまりはクラスです(笑)
参考:functor-monad-applicative.js
しかしながらコードを見比べてみると、大差がないところが山ほどあることに気が付くでしょう。
そうです。
そこを埋めるだけで、非純粋関数型言語、javascriptの完成です!
関数型プログラミングが分かりやすいわけ
文脈に依存したプログラミングをしよう!
我々の思考は何に依存しているか?
それは文脈です。
可読性の高いプログラムというのは、つまり文脈として分かりやすいということです。
何をしているのかが自明なプログラムにコメントは必要ありません。
コメントが必要なソースコードは抽象度が低く、ソースコードによって意味を伝えることができないのです。
モナドは、その手続きをそのまま文脈として書き下すための規則だと理解しています。
だから、Objectは単射にも対応するmapができるべきです。もちろん、圏として扱えるbindもね
以上とりとめもなく書きましたが、以前書いたライブラリにde.jsというのがあります。今は、サンプル用のソースコードのほうしか更新していませんが;
そして次回ライブラリは、もっと純粋関数型言語に近いものを提供できると確信しています。
そう 私にはやらなくてはならないことがある!
以上
お付き合いいただき、ありがとうございました。