バールーフ・デ・スピノザ(Baruch De Spinoza, 1632年11月24日 - 1677年2月21日)は、オランダの哲学者、神学者。一般には、そのラテン語名ベネディクトゥス・デ・スピノザ(Benedictus De Spinoza)で知られる。デカルト、ライプニッツと並ぶ合理主義哲学者として知られ、その哲学体系は代表的な汎神論と考えられてきた。また、ドイツ観念論やフランス現代思想へ強大な影響を与えた。
スピノザの汎神論はプラトン哲学的な一元論でもあり、後世の無神論(汎神論論争なども参照)や唯物論(岩波文庫版『エチカ』解説等参照)に強い影響を与え、または思想的準備の役割を果たした。生前のスピノザ自身も、神を信仰する神学者でありながら、無神論者のレッテルを貼られ異端視され、批判を浴びている。
スピノザの肖像は1970年代に流通していたオランダの最高額面の1000ギルダー紙幣に描かれていた。
純粋関数型プログラミング言語 spinoza
JavaScriptでつくられた、
JavaScriptで動作する、
純粋関数型プログラミング言語
spinoza (スピノザ)。
開発者である筆者の科学的世界観、宗教観である「汎神論」を形成した
哲学者スピノザをリスペクトした命名です。
spinoza Programming Language
spinoza
- is a Functional Reactive Programming (FRP) language
- employs Lazy evaluation strategy
- runs on JavaScript Engines (browsers & node.js)
- is written in JavaScript
spinoza 3.0.2
http://libraries.io/npm/spinoza
spinoza pure functional programming language
Homepage: https://github.com/kenokabe/spinoza
Platform: npm
Language: JavaScript
License: MIT
View on registry: https://www.npmjs.com/package/spinoza/
Hello world
spinoza.world = $('hello')(out);
spinoza.world> [ ‘hello’ ]
スピノザの汎神論はプラトン哲学的な一元論、
つまり数学世界の論理への一元論です。
何をどう一元化したのか?というと、
デカルトが「我思う故に我あり」と方法的懐疑の末に見出した
疑いきれない我々がもつ意識、人間の【精神世界】
そこから合理的に導出したプラトン哲学で語られるイデア論の【論理世界】
あともちろん、デカルトが終生解決できなかった、この我々の目の前に広がる【物質世界】
の3つの要素をすべてイデアの世界の論理へ一元化したのでした。
spinoza.world = $('hello')(out);
この方程式の左辺の
spinoza.world
は【物質世界】の「現在の事象」です。
この方程式の右辺の
$('hello')(out)
は【論理世界】の「論理」です。
この方程式の左辺と右辺が等しい、と決めたのはプログラマなので
=
は【精神世界】における人間的行為である「計算」です。
これら【論理世界】【物質世界】【精神世界】の3つの世界は、
コードという【論理世界】の「論理」として、
コード上で表現される数学の方程式により一元化されています。
$('hello')(out)
は、純粋な「論理」です。
これ自体は、【論理世界】にある「論理」でしかなく、
これ自体では【物質世界】には全く反映されません。
しかし、
spinoza.world =
と【物質世界】の現在事象と等しい、
と関係性を【精神世界】の人間の意識が規定すると
$('hello')(out)
という【論理世界】の「論理」がはじめて
【物質世界】の現在事象として「物質」化されます。
つまり「計算」されます。
spinoza.world> [ ‘hello’ ]
とコンソールに表示されますが、
「論理」からそういう「副作用」として
この【物質世界】にあるコンソールで「物質」化されたという意味です。
この「副作用」は(out)
という「論理」により引き起こされています。
$('hello')(out)
というコードならば、
「論理」がただそこにあるだけで、「計算」されません。(遅延評価)
spinoza.world = $('hello');
というコードならば、
「計算」という「物質」化をしても、
$('hello')
という「論理」が計算機内部で「計算」されるのみで、
コンソールには何も表示されません。
spinoza npm test
$('hello');
// no computing, lazy evaluation
spinoza.world = $('hello');
// computing, but no output
spinoza.world = $('hello')(out);
// ['hello']
spinoza.world = $('------------')(out);
spinoza.world =
$('one')(out)
($('two')(out))
($('three')(out));
//[ 'one' ]
//[ 'two' ]
//['three']
spinoza.world =
($('=================')(out))
($('hello')('world')(out))
// [ 'hello', 'world' ]
($('------------')(out))
($('hello')(out)(out))
// ['hello']
// ['hello']
($('------------')(out))
($('hello')(out)('world')(out))
// ['hello']
// [ 'hello', 'world' ]
($('------------')(out))
($(1)(2)(3)(out))
// [ 1, 2, 3 ]
($('------------')(out))
($(1)(2)(3)(plus10)(out))
// [ 11, 12, 13 ]
($('------------')(out))
($($(1)(2)(3)(plus10))(out))
// [ 1, 2, 3, [Function] ]
($('=================')(out));
===== spinoza =====
mode: node/io.js
spinoza.world> [ ‘hello’ ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ ‘one’ ]
spinoza.world> [ ‘two’ ]
spinoza.world> [ ‘three’ ]
spinoza.world> [ ‘=================’ ]
spinoza.world> [ ‘hello’, ‘world’ ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ ‘hello’ ]
spinoza.world> [ ‘hello’ ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ ‘hello’ ]
spinoza.world> [ ‘hello’, ‘world’ ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ 1, 2, 3 ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ 11, 12, 13 ]
spinoza.world> [ ‘————’ ]
spinoza.world> [ 1, 2, 3, [Function] ]
spinoza.world> [ ‘=================’ ]
圏論の考え方とは?
圏論とは、もともとは、
【数】というものの代数的構造を論じるための数学理論です。
圏論で考える「【数】というものの代数的構造」とは?
【数】というのは、
無限に自己参照する再帰構造になっている「何か」です。
「1たす1」
で、
「1」という【数】
と
「たす1」という【数への操作】
が、まったく同じものであるという
【数】=【数への操作】
と、無限に自己参照する再帰構造になっている「何か」であり、
こういう代数構造を論じるのが「圏論」のはじまりです。
圏論で考える「【数】というものの代数的構造」をそのままプログラミングに適用してやると?
【数】
と
【数への操作】
はまったく同じものです。
プログラミングの言葉で、まったくそのまま言い換えると、
【値】
と
【値への操作】
はまったく同じものです。
また言い換えると、
【値】
と
【関数】
はまったく同じものです。
また言い換えると、
【集合】
と
【写像】
はまったく同じものです。
関数型プログラミングとは、【集合】と【写像=関数】で論理操作を繰り返す数学的なプログラミング手法である
関数型プログラミング言語では、
【関数】が【値】(オブジェクト)として扱える、
【関数】が「ファーストクラス・オブジェクト」であるのは、
プログラミングの土台として存在する数学の代数構造で、
【数】
と
【数への操作】
あるいは
【値】
と
【関数】
あるいは
【集合】
と
【写像】
の区別が一切ない、同じものである、という根源的な原理をそのまま反映しているのです。
純粋関数型プログラミング言語「spinoza」
以上のような極めてかんたんで至極明快な事実をそのままプログラミング言語としてJavaScriptで実装したのが、
純粋関数型プログラミング言語「spinoza」である、ということになります。
【値】
と
【関数】
はまったく同じものである必要があるので、
いくら、JavaScriptという関数型プログラミング言語では関数がファーストクラスになっているからといっても、あくまで
【値】≠【関数】
と別々の存在として扱われてしまっています。
これでは我々が希求する「純粋関数型」のプログラミング言語としてははかなり都合が悪いので、
JavaScriptでも徹底的に、
【値】=【関数】
となるようにハックしてやります。
spinozaの基本構造
spinozaの基本構造はもちろん
【値】であり【関数】であり、その両者の区別がまったくない「何か」です。
代数の基本構造として
【数】が【数への操作】とまったく区別がつかない「何か」であることを論じる
「圏論」と同じはなしです。
Lispデータ構造の問題点
ジョン・マッカーシーが開発したLISPは
(関数 引数 引数 引数)
という
S式
で表記され、プログラミング構文が存在しません。
> (+ 1 2)
3
データ=コード
コード=データ
という(一見)美しい構造で、コードを変更するにはデータを変更すればよい、というコード自身を第一級(ファーストクラス)オブジェクトとして扱うことができます。
最近、巷で若干注目を集めている、Javaでも実装されはじめた リフレクション
の最上級機能を言語構造として先天的に実装しているようなもので、自己定義する人工知能研究の分野(マッカーシーの専門分野)でよく使われてきたようです。
しかし、私がLISPを関数型言語の大御所として試すなかで問題だと思った事をざっくばらんに書きます。
すでに【脱アルゴリズム宣言】シリーズで述べたように、関数型パラダイムは、まず最初にデータをまるごと用意し、そこに関数操作を加えていくという宣言をするという思考・指向でした。
こういうデータをまるごと用意する、データのコレクション、リストという発想は、LISPのリストがオリジナルなのですが、遺憾なことに
(関数 引数 引数 引数)
っていうのが命令型パラダイムであるのに気づくでしょうか?
(Do what what what)
という構造になっている。
関数型パラダイムであるならば、こう書くべきでしょう。
(What Do Do Do)
(データ 関数 関数 関数)
そして、実際のところ
(関数 引数 引数 引数)
というデータ構造のために様々な目に見える弊害がLISP/Schemeにはあります。
(関数 引数 引数 引数)とS式の最初が(データでなく)関数と決め打ちしているので、
(データ データ データ) たとえば
(1 2 3)
というデータをそのまま書くとエラーになるんですね。だってまず 1
を関数として実行しようとするけど、関数ではないので。
すべてがデータでありコードであり、コード自身を第一級(ファーストクラス)オブジェクトとして扱うことができる、という看板の割にあまりにもお粗末な結果です。
これを回避するために、
>(list 1 2 3)
(1 2 3)
という、見た目、カッコの位置がずれてデータ構造が変わってしまう方法
だったり
カッコの位置が一緒のデータ構造を維持しようと思えば、
> (quote (1 2 3))
(1 2 3)
あるいは、quoteのショートカット記号を用いて
> '(1 2 3)
(1 2 3)
と書く必要があります。このクオート記号すぐ打つの忘れるんですよね。非常に面倒くさい。美しくない。
そしてよく考えてみると、S式の要件定義によれば、
(関数 引数 引数 引数)
なので、
この
(quote (1 2 3))
の中身のかっこ(1 2 3)
はS式じゃないだろ!ってことになります。
そもそも(1 2 3)ってそのまま書いたらエラーになるから、quote付けたけど、定義どうりならばどっちにせよ無理で、
最初の
(list 1 2 3)
って書くしか整合性を保つ方法がない!ってことになります。
どうなってるのか?
実は、
(quote (1 2 3))
の場合、引数である
(1 2 3)
っていうのは、S式として評価されません。
S式でない評価しない特別なデータとして扱います。例外です。
例外、美しくないですね。余剰なルールが追加されるわけで単純さが損なわれるからです。
こんな調子では、
「すべてがデータでありコードであり、コード自身を第一級(ファーストクラス)オブジェクトとして扱うことができる」
と鵜呑みにして統一的に操作できると突き進んでも、いろいろ面倒なパッチを加えながらやるしかない未来が待ち受けているのは明々白々な状況です。
命令型オリエンテッドなS式の表記
破綻したデータ表現
どうにか回避策は無いものか?と試行錯誤しましたが
「ありませんでした」
「そして根本的な理由がわかりました」
S式のリストは、
Singly_linked_list
というリスト構造になっています。
LISPのすべてを束縛するS式の表記は、このSingly_linked_list
というリスト構造と等価であり、問題を解決するにはここからどうにかしないといけない。
LISPのリストで
((a b c)(d e f)(g h i))
は、
http://www.ki.nu/OHP/dot.emacs/list-drawing.html
(ToDo 図作成)
のようになっており、データの末尾を示すため終端にnilという空データをにつけます。
これは美しくない。
- データの末尾を示すため終端にnilという空データをにつける
というのもルールの一つです。
このルールどおりのものをPureList(純リスト)とし、LISPのS式はそれで構成されているのですが、このルールをぶちやぶって、任意のアトムを終端につけることだって可能です。この場合は
PureListじゃないので各種操作は破綻する。
セルを自由自在に組み合わせられる、柔軟な表現方法だとおもいきや、こういうルールがある。
そしてルールどおりにするならば、新たなリストを既存のリストに結合する際には、終端のnilを一旦外し、そこに接続するという2ステップの置換になる。
自由に接続じゃなくて、置換です。
何かがおかしい、何もかもがしっくりこない、と思ったので、思案の上、自分が理想とする純粋関数型言語をJavaScript上で書きました。
LISPを純粋関数型言語として全面的に書きなおす。
LISPと逆方向のリスト構造を基盤とする。
リストはEmplyPair
という無限再帰構造をもつ0
に相当するペアから始まる任意の構造である。
終端に特別な操作がない、特別ルールがないのですべての構造がPureである。
遅延評価であり、必要な構造のみ随時評価されていく。
関数はファーストクラスオブジェクトであり、さらにLISPのように関数とデータの区別はしない
すべての関数はデータである。
すべてのデータは関数である。
(1 2 3)
というデータは(1 2 3)
とクオート無しでクリーンにデータどおり表記され遅延評価される。。
もはやLISPとは別物の新言語である。
JSで書かれている、JSで動作する。
そこで私はLispのリストデータ構造を逆にしてみました。
こういうパーツがあるところまでは同じ。
でも、最初のパーツは必ず自分自身を参照させることにした。
要するに、リスト構造の頭に、数学の0(ゼロ)に対応するものを用意した。
こいつは、当然、無限再帰構造を成します。
数学の0が無限と対称になっているのと同じ構造です。
この0もしくは無限を起点に
こうやってどんどん別のパーツを接続していけば、
何をどうやろうと、全部が全部「純リスト」になります。
ターミネーターをつける置換も必要ありません。
【値】=【関数】なので、
【値】を【関数】として作用してやると、
自分自身を新たに含めた【値】=【関数】という配列になります。
[ 1 ]
に[ 2 ]
を作用させると、[ 1, 2 ]
になります。
[ 1, 2 ]
に[ 3 ]
を作用させると、[ 1, 2, 3 ]
になります。
あらゆる階層でこの無限ループになります。
リスト構造の頭に、数学の0(ゼロ)に対応するパーツ
数学の0が無限と対称になっているのと同じ構造の無限再帰構造です。
spinozaによる「評価=計算」
【値】であり同時に【関数】であるものは、
「計算」される必要があるのですが、
同じものなので、唯一の「計算機」しか必要ありません。
それがcompute
です。
いわゆるEVALとAPPLYを融合した唯一の「計算機」です。
compute
は当然無限再帰構造をなします。
数も操作も、
値も関数も、
まったく同じもので自分自身を参照する無限再帰構造になっているのだから、
それを計算する「計算機」だって無限再帰構造になるんですね。
実際「1」っていう数は代数の世界で、
無限再帰構造になっているというのは最初から説明しているとおりです。
論理の世界ではそうなんです。
しかし、プログラミングの世界では、
「1」は「1」としてしかもはや表現のしようもないもので、
「1」を延々と計算すること、物質化することは不可能ですし、
そんなことをする必要は一切ないわけです。
数学でも「1」は紙に「1」って書いてしまうだけで、
1+1というような問題を計算するときに、
「1」が無限再帰構造であるからという理由で延々と無限ループの計算にはなりません。
spinozaの数学的基礎
Foundation
Inspired by John McCarthy’s LISP
spinoza is founded on an inverted data structure of
Singly linked list and S-expression.
Pair
This is the fundamental unit of spinoza.
Pair
has a pair of hands to point a pair of any objects.
Pair points a pair of objects
Now, a Pair
points objects: a
and b
.
Pair notation
When a Pair
points objects: a
and b
, it’s expressed as {a b} in Pair notation
.
Pair can point itself
Empty Pair
When a Pair points itself, since it’s a form of Self-reference, an Infinite recursion occurs.
Accordingly, the Pair notaion
is { { {…} {…} } { {…} {…} } }, so we simply express the entity as { }, and let’s call it Empty Pair
.
Push Pair
A Pair
can point another Pair
so that we can joint Pair
s.
Now let a pair
point another Pair
and 5
by each hands.
Let’s call this special action Push
.
In this case, we push
5 to an Empty Pair
.
The Pair notation
is { {} 5 }.
Push another Pair
In the same manner, we can push
another Pair
.
We push
2
to the previous sequence.
The Pair notation
is { { {} 5 } 2 }.
Push to any sequence
Sequence
Here, spinoza explicitly defines a term Sequence
for this form.
Please note this is the same term and meaning of Sequence in Mathematics.
At the same time, instead of Pair notation
: { { { {} 5 } 2 } 7 }, it can be simply expressed as ( 5 2 7 ).
Push function
A Pair
can point function
.
Accordingly, we can push
function
to any Sequence
.
In this case, we push
a function
to (5).
A case of Push function
When we push a function
: plus2
to (5), the result is (7).
Function is Sequence
The function
: plus2
is fundamentally some Sequence
.
plus2
consists of a Sequence
: ( plus (2) ).
(2) is an attribute Sequence
of the function
.
( 5 (plus (2)) ) is equivalent to (7).
Everything is a function and Sequence
Everything is function
in spinoza.
In this case, 3
is a function
that maps a source : ( 5 ) to a target : ( 5 3 ).
Consequently, since function
is Sequence
in spinoza, everything is Sequence
in spinoza.
Therefore, 3
is a function
and at the same time, is a Sequence
.
However, 3
is 3
. There is no other way to express than just 3
in spinoza.
Every Sequence is a result of function to Empty Pair
Function composition
Function composition is naturally expressed in a form :
( source function fucnction ) in *spinoza.
Please note the source
= ( 1 ) as a Sequence
, not 1.
1 +2 +3 = 6
spinoza has a short-cut notation : + corresponding to plus
function.
1 +(2 +3) = 6
( 1 (+ ( 2 (+ ( 3 ) ) ) ) ) = ( 6 )
0 コメント:
コメントを投稿