SlideShare a Scribd company logo
1 of 39
ウルシステムズ株式会社 
http://www.ulsystems.co.jp 
mailto:info@ulsystems.co.jp 
Tel: 03-6220-1420 Fax: 03-6220-1402 
「Lispインタープリター」勉強会 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
2014/12/03 
講師:近棟稔 
説明に利用するソースコードの場所は以下の通りです 
[短縮URL] 
http://goo.gl/wtkXro 
[URL] 
https://22662085c43898e6b7217dd85e8ec1a5e8bb286f.google 
drive.com/host/0B3XsaTcJZ4A3ZmpfNXZyZmZqR0U/
はじめに 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
1 
「プログラマーなら一度はLispを作る」という言葉は有名です。ですが、実際に作ったことがある 
人はあまり居ないようです。理由として「このような技術は実務には関係ない」とか、「作ろうと 
思っても、簡単に実現可能なほど、まとまった情報が無い」などが考えられます。 
この勉強会では、プログラミング言語としてJavaScriptを用い、実際に動作する、古風で小さ 
なLispインタープリターを、段階を追って作成します。 
JavaScriptによるLispインタープリターの実装は、最初は22行で実装した四則演算インタープ 
リターの説明から開始します。最終的にはLispのマクロをサポートした、147行のLispインター 
プリターに育て上げます。 
なお、Lisp言語を知らない人も多いと思われますので、そのような方向けに、Lisp言語の非常 
に基本的な部分から説明したいと思いますので、ご安心ください。 
Lisp言語の全機能を網羅することはしませんが、この勉強会に参加すれば、Lispインタープリ 
ターがどのように動作しているのか、なんとなく分かった状態になることを目指しています。そして、 
それが分かれば、プログラミング言語を見る目が少し変わると思います。
今回説明するLispインタープリターの由来 
 Peter Norvig による、「(How to Write a (Lisp) Interpreter (in Python))」を参考にしました。Python 
で作成されており、たった113行でインタープリターが実装されています。 
http://norvig.com/lispy.html 
http://norvig.com/lispy2.html 
 Peter Norvigは、GoogleにてResearch Directorをやっている人です。また、UdacityというWeb上の 
オンラインコースでArtificial Intelligenceなどを教えています。TEDにて公演を行ったこともあります。 
(ちなみに近棟もUdacityでNorvigの授業を受けました) 
 この勉強会で説明するのは、勉強会用に特別に作成したLispインタープリターです。 
JavaScriptを用いて実装しました。文法は、Clojureから借用しています。言語の名前はmylispと名 
付けました。最終的なコード量は147行になりました。 
なお、コードエディター部分に関しては、CodeMirror (http://codemirror.net/) を利用しています。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
2 
http://www.ted.com/talks/peter_norvig_the_100_000_student_classroom
mylispの全体像(147行) 
[マクロ展開処理部分(16行)] 
ソースコードを前処理する、「マクロ」という機能を提供します。 
C言語のマクロと意味的には同じですが、Lispのマクロは非常に強力なため、 
ソスコードジェネレータであると捉えたほうが正確です。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
3 
[パーサー部分(24行)] 
ソースコード文字列をAST(抽象構文木)の構造に組み立てます。 
[インタープリターの変数格納用コンテナー(9行)] 
変数や関数を格納するためのコンテナーを用意します。 
[ASTを読みながら、プログラムの実行を行う部分(34行)] 
ASTを読みながら、プログラムを実行します。インタープリターの中核部分です。 
[組み込みライブラリー(60行)] 
足し算、引き算など、プログラムを作る際に最低限無いと困る処理を 
記述した部分です。
四則演算インタープリター 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 4
四則演算インタープリターの全体像 
 以下の22行の実装で四則演算インタープリターが作れます。 
手始めに、このインタープリターの詳細な解説を次ページ以降で説明していきます。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
5 
プログラムの実行を行う部分 
組み込みライブラリー
四則演算インタープリターの使い方 
 この四則演算インタープリターには、前もって5つの関数が用意されています。新たな関数を新規に定義すること 
や、変数を定義することは今のところ出来ません。前もって用意されている5つの関数は以下のものです。 
 ここで、Javaなどの言語では関数名に使えない「+」などの記号が関数名になっている事に違和感を覚えるかもし 
れません。ただ、Lispではしばしばこのような記号を関数名として使用します。ちょっと名前の付け方が違う程度で 
あると思ってください。たとえば「add」のような関数名の代わりに「+」という名前の関数を付けます。 
 四則演算インタープリターを使った計算は、以下のように行います。 
+関数をadd関数として記述した場合、 
JavaScript的に書くと、add(1, 2, 3) 
と同じ 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
6 
関数名引数処理内容 
+ 数値(可変長引数) 引数の数字の和を計算 
- 数値(可変長引数) 引数の数字の差を計算 
* 数値(可変長引数) 引数の数字の積を計算 
/ 数値(可変長引数) 引数の数字の商を計算 
mod 第一引数は分子、第二引数は分母引数の2つの数字の余りを計算 
つまり、ある関数を実行したい場合は、 
配列の先頭要素が関数名を入れ、 
第二要素以降に引数を入れるとします。 
関数 
+関数をadd関数とし、/関数をdiv関数と記述した場合、 
JavaScript的に書くと、add(1, div(1, 2)) と同じ 
[関数名, 引数1, 引数2, 引数3] 
次ページ以降で、四則演算インタープリ 
ターの中身の説明をしていきます。
変数や関数のグローバル変数領域:globalEnv 
 インタープリターに限らず、ほとんどのプログラミング言語で共通することとして、変数や関数を格 
納するための空間が用意されています。この空間に、名前をキーとして、値を取り出せるようにした 
り、名前をキーとして関数の実装を取り出せるようにしたりします。 
このインタープリターでは、そのような空間としてglobalEnvというオブジェクトを用意しています。構 
造は単なるHashMapです。名前をキーとして値や関数の実装を取り出せるようになっています。 
 単純な計算であればglobalEnvの呼び出しでも可能です。 
 このglobalEnvというHashMapは、以降の説明でも出てきます。globalEnvは、ひとことで言うと「グ 
ローバル変数領域」なので、このインタープリターの最終形まで存在し続けます。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
7 
+関数をadd関数として記述した場合、 
JavaScript的に書くと、add(1, 2, 3) と同じ 
mod(5, 3) と同じ
インタープリターの心臓部:evaluate 
 ほとんどのインタープリターの心臓部はevalやevaluateという関数で実装されています。JavaScript 
のevalもその1つです。以下は四則演算インタープリターのevaluate部分です。 
 上記のコードの処理内容を日本語で記述すると、以下のようになります。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
8
四則演算インタープリターの計算の進行例: 
入力がevaluate(['mod','5','3'], globalEnv); の場合 
 evaluate(['mod','5','3'], globalEnv); 
↓ 
 'mod'と'5'と'3'がevaluate(x, globalEnv)のxとして代入される。それぞれ以下の様になる。 
evaluate('mod', globalEnv) → function(num, div) {return Number(num) % Number(div);} 
evaluate('5', globalEnv) → '5' 
evaluate('3', globalEnv) → '3' 
↓ 
 mod(5, 3)が計算される。より正確には、mod.apply(null, ['5', '3']) が実行される。このapplyとい 
う関数の意味は、mod('5', '3') と同じ。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
9 
['mod','5','3'] 
[mod関数の実装,'5','3'] 
mod関数の実装に引数('5','3')を渡して実行
四則演算インタープリターの計算の進行例: 
入力がevaluate(['+', '1', ['mod','5','3']], globalEnv); の場合 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
10 
['+', '1', ['mod','5','3']] 
[+関数の実装, '1', ['mod','5','3']] 
[+関数の実装, '1', [mod関数の実装,'5','3']] 
[+関数の実装, '1', mod関数の実装('5','3')] 
[+関数の実装, '1', '2'] 
+関数の実装('1', '2') 
3
そもそもLispとは? 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 11
Lispは1958年に発明された歴史ある言語です 
 Lispは1958年にJohn McCarthyによって発明されました。時代的にはコンピュータの黎明期にあた 
ります。非常に歴史のある言語です。関数型言語であり、なおかつ公式に標準化された最初のオ 
ブジェクト指向言語でもあります。 
太平洋戦争(3年10ヶ月) 
 Lispは、プログラムで扱う主たるデータ構造の1つを 
リスト構造とし、また、プログラム自身をリスト構造の入れ子 
で表現する言語です。プログラムコードはデータなので、 
プログラムを機械的に(プログラムによって)変形したり 
自動生成したりしやすいという特徴を持ち、ここがLispの 
最も大きな強みとなっています。 
言ってみれば、Lispは、コードの自動変形・自動生成の 
機能を内蔵したプログラミング言語です。 
このコードの自動生成機能は、「マクロ」と呼ばれています。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
12 
1957 
Fortran 
John McCarthy 
1959 
COBOL 
(google画像検索より引用) 
1946 
ENIAC 
1936 
Alan Turingの 
Turing Machine 
(仮想機械) 
1947 
ノイマン型 
アーキ 
テクチャ 
1941 
Zuse Z3 
世界初の 
コンピュータ 
1958 
LISP 
実装 
(構想は1956年) 
5年5年10年
四則演算インタープリターに 
条件分岐「if」を導入 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 13
evaluate関数が条件分岐「if」を解釈できるようにします。 
 今までのevaluate関数に加筆して、「if」を解釈するようにしたものを以下に示します。 
 実行例 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
14 
追加部分 
(false ? 2 : 3) 
と同じ
「if」の利用例:globalEnvにブール値関数(true/falseを返却する関数)と 
alert関数を追加して試す。 
 ifの条件に利用可能な関数が無いため、globalEnvに以下の様に追加します。 
 JavaScriptのalert関数(ダイアログを出す関数)を利用した例は以下のようになります。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
15 
追加部分
四則演算インタープリターに 
逐次実行「do」を導入 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 16
evaluate関数が逐次実行「do」を解釈できるようにします。 
 「do」の導入のためには、do関数をglobalEnvに追加します。 
 そもそも逐次実行とは?? 
プログラムはループなどが無ければ、上の行から下の行に向かって順番に実行されます。これが 
逐次実行です。「do」の場合は、この逐次実行実行に加えて、最後に計算した計算結果を返すとい 
う役割もあります。 
 「do」の簡単な使い方 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
17 
追加部分 
上から順にalertを表示し、 
doの最後に指定した「5」を 
返却している。 
[注] Common Lisp では、「do」はループを意味しますが、 
Clojureを真似て、mylispでは逐次実行の意味としています。
定数をプログラムから 
作成可能にする 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 18
「def」により、evaluate関数内でglobalEnvに対して新たな変数を 
定義可能にします。defは定義することを意味するdefineの略です。 
 globalEnvに新たなkey/valueを定義可能にするための「def」を処理する機能をevaluate関数に追 
加します。そのために、HashMapであるenvに指定されたオブジェクトを代入します。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
19 
追加部分
「def」の利用例 
 「def」を利用し、PIを定義してみます。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
20 
PIを定義していない場合、PIを評価しても、 
PIというシンボルをそのまま返却します。 
PIを3.14159と定義します。内部的には、 
globalEnvのHashMapに代入しています。 
PIを再度評価すると、今度は3.14159が返ります。 
globalEnvに、「PI」というキーで「3.14159」が入っていることが分かります。
関数をプログラムから 
作成可能にする 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 21
evaluate関数内で無名関数を作成可能にします。 
 いよいよインタープリター内で関数を作成可能にします。実現方法としては、JavaScriptの関数オブジェクトを作成 
することで多くの複雑な部分を単純化しています。無名関数の作成は、ここではJavaScriptの関数の生成に置き 
換わっているに過ぎません。最低限やらなければならないことは、実引数を仮引数に代入する作業となります。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
22 
追加部分 
[悪] 
ここでグローバル変 
数領域であるenv 
(すなわちglobalE 
nv)に仮引数をキ 
ーに実引数を代入 
してしまっています。 
要改善点です。
「fn」の利用例 
 「fn」によって関数オブジェクトを作成し、そのオブジェクトを「def」によってincrementというキーに保 
持させてみます。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
23 
JavaScriptにおける 
var increment = function(x){return 1 + x;}; 
このように、 
JavaScriptの 
関数オブジェクト 
へと評価されます。 
increment(2)を呼び出してみます。 
1 + 2 の計算結果である3 が返ってきます。 
しかし、現在の関数の実装では、引数の値を直接globalEnvに代入しているために、 
関数実行後もglobalEnvに関数の引数が残ってしまいます。 
これを解決するために必要なのは、グローバル変数領域であるglobalEnvのHashMapに 
引数を保持させるのではなく、メソッド呼び出しに閉じた、階層化されたHashMapを使う必要があります。 
つまり、呼び出し階層が1つ深くなると、その階層専用の領域を持つ必要があります。
変数が必ずglobalEnvに代入される事の問題点 
 現状、何かの値や関数に名前を付ける(defする)場合、必ずglobalEnvに代入を行っています。 
このような仕様では、具体的には以下のような問題が発生します。 
1. 関数内でdefを使うと、「関数ローカル」な変数を定義しようとしても、必ずglobalになります。 
(この挙動は、JavaScriptでvarを付けずに変数定義した場合と似ています。) 
2. 関数呼び出し時に渡した値と引数の名前とのマッピングもglobalEnvに登録しているため、関数呼 
び出しをするたびに引数で渡した値がglobalEnvに格納されてしまいます。 
JavaScriptにおける、このような挙動をさせたい。 
つまり、「a」も「b」も1や2を格納していない状態になるべ 
き。しかし今はaに1が入り、bに2が入るような挙動をして 
しまう。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
24 
結局、globalEnvを使った変数のマッピングを 
していてはダメで、関数ローカルなマッピングが 
必要!
関数内の変数を「ローカル」にする 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 25
シンボル(変数名)でオブジェクト(変数や関数)を引き出す仕組みを改善する。 
(現状の単純なHashMapから、ローカルスコープを持ったHashMapへ) 
 単純なHashMapから、ローカルスコープを持ったHashMapへ変更するため、以下のようなデータコ 
ンテナを作ります。 
 このデータコンテナを用いて、以下のような構造を作れるようにします。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
26 
globalEnv 
env2 
env3 
env1 
a=0 
a=1 
a=3 
globalEnvはグローバル変数領域とし、 
env1, env2, env3 はそれぞれ関数 
ローカルの変数領域とします。 
それぞれの関数ローカルの変数領域 
(すなわち、ローカル変数領域)は、 
自身の変数領域に該当シンボルが無い 
場合、よりグローバル側の環境を探しに 
行きます。
関数のローカルスコープを持つようにevaluateを修正 
 全体的にenv.bindingに対する処理に変更します。また、関数呼び出しの際に関数ローカルのenvを作るように修 
正します。変数を探す際にはfindEnvを用いてenvの階層構造をさかのぼって値を探すように修正します。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
27 
[改善] 
関数呼び出し毎に 
新たなHashMapを 
作ることで、グローバ 
ル変数領域を汚さない 
ようにする。また、「内」 
から「外」の変数は見え 
るようにする。
可変長引数のサポート(余談) 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 28
可変長引数のサポート(余談) 
 サポートしたい可変長引数の文法 
func(a & b) という関数を作り、func(1, 2, 3)という呼び出しをすると、 
引数a と引数b に、それぞれ以下の情報が入るようにしたい。 
a ← 1 
b ← [2, 3] 
 可変長引数をサポートする前の姿 
 可変長引数をサポートした後の姿 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
29 
← Javaにおけるfunc(int a, int... b) {...} のような意味 
mylispでの書き方に従うと・・・ 
["def", "func", ["fn", ["a", "&", "b"] ] 
となる。 
「&」が登場した後の引 
数に、残りの実引数を 
リストとして保持する。
可変長引数の利用例(余談) 
 以下に可変長引数の利用例を示します。「&」に特別な意味を持たせることで、このように可変長引 
数を実現することが可能です。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
30 
JavaにおけるalertMsg(String message, int... xs) {...} のような意味 
このように、任意の数の引数を与えることが可能です。 
引数message ← "テスト" 
引数xs ← ["1","2","3"]
プログラムの変換・生成のために 
マクロを導入 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 31
evaluateの前処理としてプログラムを変形するのがマクロの仕事 
 今まで見てきたmylispは、ソースコードがJavaScriptの配列表現でした。よって、JavaScriptの配列 
操作を行えば、自由に変形することが可能です。この変形操作がマクロの本質です。 
マクロ導入前マクロ導入後 
['+', '1', ['mod','5','3']] 
evaluate ・・・何かに変形・・・ 
 マクロの利用例として、以下のような事が考えられます。 
 ソースコード上に出現する退屈なコードの記述を、少ない記述で自動生成するため。 
 DSLを作るため。(DSLを作れば記述を簡素化可能) 
 パフォーマンスを出すために、既存コードを別の構造に変換するため。 
 パフォーマンスを出すために、特定の計算をevaluate前に計算済みの状態にしてしまう。 
 「オブジェクト指向」など、新たな言語上のパラダイムが世の中に登場した際に、言語自身を拡張するため。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
32 
['+', '1', ['mod','5','3']] 
evaluate 
3 
3 
マクロ展開
マクロを定義し、同時にマクロを展開する(プログラムコードを変換する)ために 
は、globalEnvとは別にmacroTableを作ります。 
 マクロ名をキー、プログラムコードを変換する関数を値とするHashMapを作ります。このHashMapをmacroTable 
と名付けます。 
 一方で、マクロはJavaScriptの配列をさまざまに操作する必要があるので、配列の操作関数を一式導入します。 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
33
マクロの利用例 
 マクロの利用例として、条件分岐の機能を持つ「when」をマクロで実装してみます。 
 実行例を以下に示します。 
 実行時には、以下の様にソースコードが変形され、evaluateされます。 
["if", "true", [do, ["+", "2", "3"]], "null"] 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
34 
["when", "true", ["+", "2", "3"]] 
evaluate 
5 
マクロ展開 
ソースコードの変換方法をmacroTableに定義 
上のマクロを使って展開した後に実行
JavaScriptの配列表現をやめ、 
文字列表現へ 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 35
JavaScriptの配列表現は見づらいので、標準的なLisp表現を解釈可能にしま 
す。そのためには、文字列のパーサーを書く必要があります。 
 文字列のパースを行い、JavaScriptの配列を組み立てる処理は以下のように書けます。 
文字列JavaScriptの配列形式(ASTと呼ばれる) 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
36 
(+ 1 (mod 5 3)) ['+', '1', ['mod', '5', '3']] 
parse
まとめ 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 37
インタープリターの全体処理イメージ 
 インタープリターは、以下の様な処理フローで処理されます。 
 Lispで特殊なのは、マクロを用いて一旦プログラムが変形されたり、生成されたりするフェーズがあ 
ることです。このようなフェーズの存在は、一般的にはC言語のプリプロセッサーと同一といえば同 
一ですが、C言語のプリプロセッサーなどよりも非常に強力なため、Lispを特別なものにしています。 
 なぜLispのマクロが強力なのかといえば、プログラムがリストの入れ子構造で表現されているため 
に、マクロからプログラムコードを扱いやすいという特性によります。 
(when true (+ 2 3)) 文字列 
["if", "true", ["+", "2", "3"], "null"] 
ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 
38 
["when", "true", ["+", "2", "3"]] 
JavaScriptの配列形式(ASTと呼ばれる) 
parse 
マクロ展開←この処理はソースコードの自動生成といっしょ 
evaluate 
5

More Related Content

What's hot

プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けーTanUkkii
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)x1 ichi
 
TensorFlow XLAは、 中で何をやっているのか?
TensorFlow XLAは、 中で何をやっているのか?TensorFlow XLAは、 中で何をやっているのか?
TensorFlow XLAは、 中で何をやっているのか?Mr. Vengineer
 
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」fukuoka.ex
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しようUnity Technologies Japan K.K.
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11nekko1119
 
TensorFlow XLAの可能性
TensorFlow XLAの可能性 TensorFlow XLAの可能性
TensorFlow XLAの可能性 Mr. Vengineer
 
15分でざっくり分かるScala入門
15分でざっくり分かるScala入門15分でざっくり分かるScala入門
15分でざっくり分かるScala入門SatoYu1ro
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriYuta Okamoto
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかYuki Miyatake
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由kikairoya
 

What's hot (15)

プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)
 
boost tour 1.48.0 all
boost tour 1.48.0 allboost tour 1.48.0 all
boost tour 1.48.0 all
 
TensorFlow XLAは、 中で何をやっているのか?
TensorFlow XLAは、 中で何をやっているのか?TensorFlow XLAは、 中で何をやっているのか?
TensorFlow XLAは、 中で何をやっているのか?
 
Thinking in Cats
Thinking in CatsThinking in Cats
Thinking in Cats
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」
【LT版】Elixir入門「第7回:Python/KerasをElixirから繋いでアレコレする」
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11
 
TensorFlow XLAの可能性
TensorFlow XLAの可能性 TensorFlow XLAの可能性
TensorFlow XLAの可能性
 
15分でざっくり分かるScala入門
15分でざっくり分かるScala入門15分でざっくり分かるScala入門
15分でざっくり分かるScala入門
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuri
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうか
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 

Viewers also liked

AspectJによるJava言語拡張 2012.09.07
AspectJによるJava言語拡張 2012.09.07AspectJによるJava言語拡張 2012.09.07
AspectJによるJava言語拡張 2012.09.07Minoru Chikamune
 
省メモリーに関するデザインパターン 2011.04.18
省メモリーに関するデザインパターン 2011.04.18省メモリーに関するデザインパターン 2011.04.18
省メモリーに関するデザインパターン 2011.04.18Minoru Chikamune
 
「Googleを支える技術」の解説 2010.08.23
「Googleを支える技術」の解説 2010.08.23「Googleを支える技術」の解説 2010.08.23
「Googleを支える技術」の解説 2010.08.23Minoru Chikamune
 
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29「グーグルの自動運転Carの技術要素」勉強会 2014.08.29
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29Minoru Chikamune
 
Stormとその周辺 2013.03.15
Stormとその周辺 2013.03.15Stormとその周辺 2013.03.15
Stormとその周辺 2013.03.15Minoru Chikamune
 
有名論文から学ぶディープラーニング 2016.03.25
有名論文から学ぶディープラーニング 2016.03.25有名論文から学ぶディープラーニング 2016.03.25
有名論文から学ぶディープラーニング 2016.03.25Minoru Chikamune
 
D3によるデータビジュアライゼーション 2013.09.13
D3によるデータビジュアライゼーション 2013.09.13D3によるデータビジュアライゼーション 2013.09.13
D3によるデータビジュアライゼーション 2013.09.13Minoru Chikamune
 
「Raspberry pi」勉強会 2015.03.20
「Raspberry pi」勉強会 2015.03.20「Raspberry pi」勉強会 2015.03.20
「Raspberry pi」勉強会 2015.03.20Minoru Chikamune
 
「機械学習 By スタンフォード大学」勉強会 2015.09.11
「機械学習 By スタンフォード大学」勉強会 2015.09.11「機械学習 By スタンフォード大学」勉強会 2015.09.11
「機械学習 By スタンフォード大学」勉強会 2015.09.11Minoru Chikamune
 

Viewers also liked (9)

AspectJによるJava言語拡張 2012.09.07
AspectJによるJava言語拡張 2012.09.07AspectJによるJava言語拡張 2012.09.07
AspectJによるJava言語拡張 2012.09.07
 
省メモリーに関するデザインパターン 2011.04.18
省メモリーに関するデザインパターン 2011.04.18省メモリーに関するデザインパターン 2011.04.18
省メモリーに関するデザインパターン 2011.04.18
 
「Googleを支える技術」の解説 2010.08.23
「Googleを支える技術」の解説 2010.08.23「Googleを支える技術」の解説 2010.08.23
「Googleを支える技術」の解説 2010.08.23
 
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29「グーグルの自動運転Carの技術要素」勉強会 2014.08.29
「グーグルの自動運転Carの技術要素」勉強会 2014.08.29
 
Stormとその周辺 2013.03.15
Stormとその周辺 2013.03.15Stormとその周辺 2013.03.15
Stormとその周辺 2013.03.15
 
有名論文から学ぶディープラーニング 2016.03.25
有名論文から学ぶディープラーニング 2016.03.25有名論文から学ぶディープラーニング 2016.03.25
有名論文から学ぶディープラーニング 2016.03.25
 
D3によるデータビジュアライゼーション 2013.09.13
D3によるデータビジュアライゼーション 2013.09.13D3によるデータビジュアライゼーション 2013.09.13
D3によるデータビジュアライゼーション 2013.09.13
 
「Raspberry pi」勉強会 2015.03.20
「Raspberry pi」勉強会 2015.03.20「Raspberry pi」勉強会 2015.03.20
「Raspberry pi」勉強会 2015.03.20
 
「機械学習 By スタンフォード大学」勉強会 2015.09.11
「機械学習 By スタンフォード大学」勉強会 2015.09.11「機械学習 By スタンフォード大学」勉強会 2015.09.11
「機械学習 By スタンフォード大学」勉強会 2015.09.11
 

Similar to 「Lispインタープリター」勉強会 2014.12.04

Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Hideki Saito
 
Swift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswiftSwift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswiftTomohiro Kumagai
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)Shin-ya Koga
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発papamitra
 
Ansible 2.0 のサマライズとこれから
Ansible 2.0 のサマライズとこれからAnsible 2.0 のサマライズとこれから
Ansible 2.0 のサマライズとこれからTakeshi Kuramochi
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門masatora atarashi
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4Shingo Inoue
 
ゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますinfinite_loop
 
SwiftでRiemann球面を扱う
SwiftでRiemann球面を扱うSwiftでRiemann球面を扱う
SwiftでRiemann球面を扱うhayato iida
 
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】株式会社ランチェスター
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験Toshio Ehara
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsShogo Sensui
 
how unext took in eclipse collections in fw
   how unext took in eclipse collections in fw   how unext took in eclipse collections in fw
how unext took in eclipse collections in fwMasahiko Kubo
 
Laravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならLaravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならShohei Okada
 
Ansible 入門 #01 (初心者向け)
Ansible 入門 #01 (初心者向け)Ansible 入門 #01 (初心者向け)
Ansible 入門 #01 (初心者向け)Taro Hirose
 

Similar to 「Lispインタープリター」勉強会 2014.12.04 (20)

Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021
 
Swift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswiftSwift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswift
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発
 
Ansible 2.0 のサマライズとこれから
Ansible 2.0 のサマライズとこれからAnsible 2.0 のサマライズとこれから
Ansible 2.0 のサマライズとこれから
 
Java8勉強会
Java8勉強会Java8勉強会
Java8勉強会
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4
 
ゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せます
 
SwiftでRiemann球面を扱う
SwiftでRiemann球面を扱うSwiftでRiemann球面を扱う
SwiftでRiemann球面を扱う
 
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
 
Lt 111217
Lt 111217Lt 111217
Lt 111217
 
ALPSチュートリアル(1) ALPSの概要
ALPSチュートリアル(1) ALPSの概要ALPSチュートリアル(1) ALPSの概要
ALPSチュートリアル(1) ALPSの概要
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.js
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
how unext took in eclipse collections in fw
   how unext took in eclipse collections in fw   how unext took in eclipse collections in fw
how unext took in eclipse collections in fw
 
Laravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならLaravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するなら
 
Ansible 入門 #01 (初心者向け)
Ansible 入門 #01 (初心者向け)Ansible 入門 #01 (初心者向け)
Ansible 入門 #01 (初心者向け)
 

「Lispインタープリター」勉強会 2014.12.04

  • 1. ウルシステムズ株式会社 http://www.ulsystems.co.jp mailto:info@ulsystems.co.jp Tel: 03-6220-1420 Fax: 03-6220-1402 「Lispインタープリター」勉強会 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 2014/12/03 講師:近棟稔 説明に利用するソースコードの場所は以下の通りです [短縮URL] http://goo.gl/wtkXro [URL] https://22662085c43898e6b7217dd85e8ec1a5e8bb286f.google drive.com/host/0B3XsaTcJZ4A3ZmpfNXZyZmZqR0U/
  • 2. はじめに ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 1 「プログラマーなら一度はLispを作る」という言葉は有名です。ですが、実際に作ったことがある 人はあまり居ないようです。理由として「このような技術は実務には関係ない」とか、「作ろうと 思っても、簡単に実現可能なほど、まとまった情報が無い」などが考えられます。 この勉強会では、プログラミング言語としてJavaScriptを用い、実際に動作する、古風で小さ なLispインタープリターを、段階を追って作成します。 JavaScriptによるLispインタープリターの実装は、最初は22行で実装した四則演算インタープ リターの説明から開始します。最終的にはLispのマクロをサポートした、147行のLispインター プリターに育て上げます。 なお、Lisp言語を知らない人も多いと思われますので、そのような方向けに、Lisp言語の非常 に基本的な部分から説明したいと思いますので、ご安心ください。 Lisp言語の全機能を網羅することはしませんが、この勉強会に参加すれば、Lispインタープリ ターがどのように動作しているのか、なんとなく分かった状態になることを目指しています。そして、 それが分かれば、プログラミング言語を見る目が少し変わると思います。
  • 3. 今回説明するLispインタープリターの由来  Peter Norvig による、「(How to Write a (Lisp) Interpreter (in Python))」を参考にしました。Python で作成されており、たった113行でインタープリターが実装されています。 http://norvig.com/lispy.html http://norvig.com/lispy2.html  Peter Norvigは、GoogleにてResearch Directorをやっている人です。また、UdacityというWeb上の オンラインコースでArtificial Intelligenceなどを教えています。TEDにて公演を行ったこともあります。 (ちなみに近棟もUdacityでNorvigの授業を受けました)  この勉強会で説明するのは、勉強会用に特別に作成したLispインタープリターです。 JavaScriptを用いて実装しました。文法は、Clojureから借用しています。言語の名前はmylispと名 付けました。最終的なコード量は147行になりました。 なお、コードエディター部分に関しては、CodeMirror (http://codemirror.net/) を利用しています。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 2 http://www.ted.com/talks/peter_norvig_the_100_000_student_classroom
  • 4. mylispの全体像(147行) [マクロ展開処理部分(16行)] ソースコードを前処理する、「マクロ」という機能を提供します。 C言語のマクロと意味的には同じですが、Lispのマクロは非常に強力なため、 ソスコードジェネレータであると捉えたほうが正確です。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 3 [パーサー部分(24行)] ソースコード文字列をAST(抽象構文木)の構造に組み立てます。 [インタープリターの変数格納用コンテナー(9行)] 変数や関数を格納するためのコンテナーを用意します。 [ASTを読みながら、プログラムの実行を行う部分(34行)] ASTを読みながら、プログラムを実行します。インタープリターの中核部分です。 [組み込みライブラリー(60行)] 足し算、引き算など、プログラムを作る際に最低限無いと困る処理を 記述した部分です。
  • 5. 四則演算インタープリター ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 4
  • 6. 四則演算インタープリターの全体像  以下の22行の実装で四則演算インタープリターが作れます。 手始めに、このインタープリターの詳細な解説を次ページ以降で説明していきます。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 5 プログラムの実行を行う部分 組み込みライブラリー
  • 7. 四則演算インタープリターの使い方  この四則演算インタープリターには、前もって5つの関数が用意されています。新たな関数を新規に定義すること や、変数を定義することは今のところ出来ません。前もって用意されている5つの関数は以下のものです。  ここで、Javaなどの言語では関数名に使えない「+」などの記号が関数名になっている事に違和感を覚えるかもし れません。ただ、Lispではしばしばこのような記号を関数名として使用します。ちょっと名前の付け方が違う程度で あると思ってください。たとえば「add」のような関数名の代わりに「+」という名前の関数を付けます。  四則演算インタープリターを使った計算は、以下のように行います。 +関数をadd関数として記述した場合、 JavaScript的に書くと、add(1, 2, 3) と同じ ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 6 関数名引数処理内容 + 数値(可変長引数) 引数の数字の和を計算 - 数値(可変長引数) 引数の数字の差を計算 * 数値(可変長引数) 引数の数字の積を計算 / 数値(可変長引数) 引数の数字の商を計算 mod 第一引数は分子、第二引数は分母引数の2つの数字の余りを計算 つまり、ある関数を実行したい場合は、 配列の先頭要素が関数名を入れ、 第二要素以降に引数を入れるとします。 関数 +関数をadd関数とし、/関数をdiv関数と記述した場合、 JavaScript的に書くと、add(1, div(1, 2)) と同じ [関数名, 引数1, 引数2, 引数3] 次ページ以降で、四則演算インタープリ ターの中身の説明をしていきます。
  • 8. 変数や関数のグローバル変数領域:globalEnv  インタープリターに限らず、ほとんどのプログラミング言語で共通することとして、変数や関数を格 納するための空間が用意されています。この空間に、名前をキーとして、値を取り出せるようにした り、名前をキーとして関数の実装を取り出せるようにしたりします。 このインタープリターでは、そのような空間としてglobalEnvというオブジェクトを用意しています。構 造は単なるHashMapです。名前をキーとして値や関数の実装を取り出せるようになっています。  単純な計算であればglobalEnvの呼び出しでも可能です。  このglobalEnvというHashMapは、以降の説明でも出てきます。globalEnvは、ひとことで言うと「グ ローバル変数領域」なので、このインタープリターの最終形まで存在し続けます。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 7 +関数をadd関数として記述した場合、 JavaScript的に書くと、add(1, 2, 3) と同じ mod(5, 3) と同じ
  • 9. インタープリターの心臓部:evaluate  ほとんどのインタープリターの心臓部はevalやevaluateという関数で実装されています。JavaScript のevalもその1つです。以下は四則演算インタープリターのevaluate部分です。  上記のコードの処理内容を日本語で記述すると、以下のようになります。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 8
  • 10. 四則演算インタープリターの計算の進行例: 入力がevaluate(['mod','5','3'], globalEnv); の場合  evaluate(['mod','5','3'], globalEnv); ↓  'mod'と'5'と'3'がevaluate(x, globalEnv)のxとして代入される。それぞれ以下の様になる。 evaluate('mod', globalEnv) → function(num, div) {return Number(num) % Number(div);} evaluate('5', globalEnv) → '5' evaluate('3', globalEnv) → '3' ↓  mod(5, 3)が計算される。より正確には、mod.apply(null, ['5', '3']) が実行される。このapplyとい う関数の意味は、mod('5', '3') と同じ。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 9 ['mod','5','3'] [mod関数の実装,'5','3'] mod関数の実装に引数('5','3')を渡して実行
  • 11. 四則演算インタープリターの計算の進行例: 入力がevaluate(['+', '1', ['mod','5','3']], globalEnv); の場合 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 10 ['+', '1', ['mod','5','3']] [+関数の実装, '1', ['mod','5','3']] [+関数の実装, '1', [mod関数の実装,'5','3']] [+関数の実装, '1', mod関数の実装('5','3')] [+関数の実装, '1', '2'] +関数の実装('1', '2') 3
  • 12. そもそもLispとは? ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 11
  • 13. Lispは1958年に発明された歴史ある言語です  Lispは1958年にJohn McCarthyによって発明されました。時代的にはコンピュータの黎明期にあた ります。非常に歴史のある言語です。関数型言語であり、なおかつ公式に標準化された最初のオ ブジェクト指向言語でもあります。 太平洋戦争(3年10ヶ月)  Lispは、プログラムで扱う主たるデータ構造の1つを リスト構造とし、また、プログラム自身をリスト構造の入れ子 で表現する言語です。プログラムコードはデータなので、 プログラムを機械的に(プログラムによって)変形したり 自動生成したりしやすいという特徴を持ち、ここがLispの 最も大きな強みとなっています。 言ってみれば、Lispは、コードの自動変形・自動生成の 機能を内蔵したプログラミング言語です。 このコードの自動生成機能は、「マクロ」と呼ばれています。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 12 1957 Fortran John McCarthy 1959 COBOL (google画像検索より引用) 1946 ENIAC 1936 Alan Turingの Turing Machine (仮想機械) 1947 ノイマン型 アーキ テクチャ 1941 Zuse Z3 世界初の コンピュータ 1958 LISP 実装 (構想は1956年) 5年5年10年
  • 14. 四則演算インタープリターに 条件分岐「if」を導入 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 13
  • 16. 「if」の利用例:globalEnvにブール値関数(true/falseを返却する関数)と alert関数を追加して試す。  ifの条件に利用可能な関数が無いため、globalEnvに以下の様に追加します。  JavaScriptのalert関数(ダイアログを出す関数)を利用した例は以下のようになります。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 15 追加部分
  • 17. 四則演算インタープリターに 逐次実行「do」を導入 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 16
  • 18. evaluate関数が逐次実行「do」を解釈できるようにします。  「do」の導入のためには、do関数をglobalEnvに追加します。  そもそも逐次実行とは?? プログラムはループなどが無ければ、上の行から下の行に向かって順番に実行されます。これが 逐次実行です。「do」の場合は、この逐次実行実行に加えて、最後に計算した計算結果を返すとい う役割もあります。  「do」の簡単な使い方 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 17 追加部分 上から順にalertを表示し、 doの最後に指定した「5」を 返却している。 [注] Common Lisp では、「do」はループを意味しますが、 Clojureを真似て、mylispでは逐次実行の意味としています。
  • 19. 定数をプログラムから 作成可能にする ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 18
  • 20. 「def」により、evaluate関数内でglobalEnvに対して新たな変数を 定義可能にします。defは定義することを意味するdefineの略です。  globalEnvに新たなkey/valueを定義可能にするための「def」を処理する機能をevaluate関数に追 加します。そのために、HashMapであるenvに指定されたオブジェクトを代入します。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 19 追加部分
  • 21. 「def」の利用例  「def」を利用し、PIを定義してみます。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 20 PIを定義していない場合、PIを評価しても、 PIというシンボルをそのまま返却します。 PIを3.14159と定義します。内部的には、 globalEnvのHashMapに代入しています。 PIを再度評価すると、今度は3.14159が返ります。 globalEnvに、「PI」というキーで「3.14159」が入っていることが分かります。
  • 22. 関数をプログラムから 作成可能にする ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 21
  • 23. evaluate関数内で無名関数を作成可能にします。  いよいよインタープリター内で関数を作成可能にします。実現方法としては、JavaScriptの関数オブジェクトを作成 することで多くの複雑な部分を単純化しています。無名関数の作成は、ここではJavaScriptの関数の生成に置き 換わっているに過ぎません。最低限やらなければならないことは、実引数を仮引数に代入する作業となります。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 22 追加部分 [悪] ここでグローバル変 数領域であるenv (すなわちglobalE nv)に仮引数をキ ーに実引数を代入 してしまっています。 要改善点です。
  • 24. 「fn」の利用例  「fn」によって関数オブジェクトを作成し、そのオブジェクトを「def」によってincrementというキーに保 持させてみます。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 23 JavaScriptにおける var increment = function(x){return 1 + x;}; このように、 JavaScriptの 関数オブジェクト へと評価されます。 increment(2)を呼び出してみます。 1 + 2 の計算結果である3 が返ってきます。 しかし、現在の関数の実装では、引数の値を直接globalEnvに代入しているために、 関数実行後もglobalEnvに関数の引数が残ってしまいます。 これを解決するために必要なのは、グローバル変数領域であるglobalEnvのHashMapに 引数を保持させるのではなく、メソッド呼び出しに閉じた、階層化されたHashMapを使う必要があります。 つまり、呼び出し階層が1つ深くなると、その階層専用の領域を持つ必要があります。
  • 25. 変数が必ずglobalEnvに代入される事の問題点  現状、何かの値や関数に名前を付ける(defする)場合、必ずglobalEnvに代入を行っています。 このような仕様では、具体的には以下のような問題が発生します。 1. 関数内でdefを使うと、「関数ローカル」な変数を定義しようとしても、必ずglobalになります。 (この挙動は、JavaScriptでvarを付けずに変数定義した場合と似ています。) 2. 関数呼び出し時に渡した値と引数の名前とのマッピングもglobalEnvに登録しているため、関数呼 び出しをするたびに引数で渡した値がglobalEnvに格納されてしまいます。 JavaScriptにおける、このような挙動をさせたい。 つまり、「a」も「b」も1や2を格納していない状態になるべ き。しかし今はaに1が入り、bに2が入るような挙動をして しまう。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 24 結局、globalEnvを使った変数のマッピングを していてはダメで、関数ローカルなマッピングが 必要!
  • 26. 関数内の変数を「ローカル」にする ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 25
  • 27. シンボル(変数名)でオブジェクト(変数や関数)を引き出す仕組みを改善する。 (現状の単純なHashMapから、ローカルスコープを持ったHashMapへ)  単純なHashMapから、ローカルスコープを持ったHashMapへ変更するため、以下のようなデータコ ンテナを作ります。  このデータコンテナを用いて、以下のような構造を作れるようにします。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 26 globalEnv env2 env3 env1 a=0 a=1 a=3 globalEnvはグローバル変数領域とし、 env1, env2, env3 はそれぞれ関数 ローカルの変数領域とします。 それぞれの関数ローカルの変数領域 (すなわち、ローカル変数領域)は、 自身の変数領域に該当シンボルが無い 場合、よりグローバル側の環境を探しに 行きます。
  • 28. 関数のローカルスコープを持つようにevaluateを修正  全体的にenv.bindingに対する処理に変更します。また、関数呼び出しの際に関数ローカルのenvを作るように修 正します。変数を探す際にはfindEnvを用いてenvの階層構造をさかのぼって値を探すように修正します。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 27 [改善] 関数呼び出し毎に 新たなHashMapを 作ることで、グローバ ル変数領域を汚さない ようにする。また、「内」 から「外」の変数は見え るようにする。
  • 29. 可変長引数のサポート(余談) ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 28
  • 30. 可変長引数のサポート(余談)  サポートしたい可変長引数の文法 func(a & b) という関数を作り、func(1, 2, 3)という呼び出しをすると、 引数a と引数b に、それぞれ以下の情報が入るようにしたい。 a ← 1 b ← [2, 3]  可変長引数をサポートする前の姿  可変長引数をサポートした後の姿 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 29 ← Javaにおけるfunc(int a, int... b) {...} のような意味 mylispでの書き方に従うと・・・ ["def", "func", ["fn", ["a", "&", "b"] ] となる。 「&」が登場した後の引 数に、残りの実引数を リストとして保持する。
  • 31. 可変長引数の利用例(余談)  以下に可変長引数の利用例を示します。「&」に特別な意味を持たせることで、このように可変長引 数を実現することが可能です。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 30 JavaにおけるalertMsg(String message, int... xs) {...} のような意味 このように、任意の数の引数を与えることが可能です。 引数message ← "テスト" 引数xs ← ["1","2","3"]
  • 32. プログラムの変換・生成のために マクロを導入 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 31
  • 33. evaluateの前処理としてプログラムを変形するのがマクロの仕事  今まで見てきたmylispは、ソースコードがJavaScriptの配列表現でした。よって、JavaScriptの配列 操作を行えば、自由に変形することが可能です。この変形操作がマクロの本質です。 マクロ導入前マクロ導入後 ['+', '1', ['mod','5','3']] evaluate ・・・何かに変形・・・  マクロの利用例として、以下のような事が考えられます。  ソースコード上に出現する退屈なコードの記述を、少ない記述で自動生成するため。  DSLを作るため。(DSLを作れば記述を簡素化可能)  パフォーマンスを出すために、既存コードを別の構造に変換するため。  パフォーマンスを出すために、特定の計算をevaluate前に計算済みの状態にしてしまう。  「オブジェクト指向」など、新たな言語上のパラダイムが世の中に登場した際に、言語自身を拡張するため。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 32 ['+', '1', ['mod','5','3']] evaluate 3 3 マクロ展開
  • 34. マクロを定義し、同時にマクロを展開する(プログラムコードを変換する)ために は、globalEnvとは別にmacroTableを作ります。  マクロ名をキー、プログラムコードを変換する関数を値とするHashMapを作ります。このHashMapをmacroTable と名付けます。  一方で、マクロはJavaScriptの配列をさまざまに操作する必要があるので、配列の操作関数を一式導入します。 ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 33
  • 35. マクロの利用例  マクロの利用例として、条件分岐の機能を持つ「when」をマクロで実装してみます。  実行例を以下に示します。  実行時には、以下の様にソースコードが変形され、evaluateされます。 ["if", "true", [do, ["+", "2", "3"]], "null"] ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 34 ["when", "true", ["+", "2", "3"]] evaluate 5 マクロ展開 ソースコードの変換方法をmacroTableに定義 上のマクロを使って展開した後に実行
  • 36. JavaScriptの配列表現をやめ、 文字列表現へ ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 35
  • 37. JavaScriptの配列表現は見づらいので、標準的なLisp表現を解釈可能にしま す。そのためには、文字列のパーサーを書く必要があります。  文字列のパースを行い、JavaScriptの配列を組み立てる処理は以下のように書けます。 文字列JavaScriptの配列形式(ASTと呼ばれる) ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 36 (+ 1 (mod 5 3)) ['+', '1', ['mod', '5', '3']] parse
  • 38. まとめ ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 37
  • 39. インタープリターの全体処理イメージ  インタープリターは、以下の様な処理フローで処理されます。  Lispで特殊なのは、マクロを用いて一旦プログラムが変形されたり、生成されたりするフェーズがあ ることです。このようなフェーズの存在は、一般的にはC言語のプリプロセッサーと同一といえば同 一ですが、C言語のプリプロセッサーなどよりも非常に強力なため、Lispを特別なものにしています。  なぜLispのマクロが強力なのかといえば、プログラムがリストの入れ子構造で表現されているため に、マクロからプログラムコードを扱いやすいという特性によります。 (when true (+ 2 3)) 文字列 ["if", "true", ["+", "2", "3"], "null"] ULS Copyright © 2014 UL Systems, Inc. All rights reserved. 38 ["when", "true", ["+", "2", "3"]] JavaScriptの配列形式(ASTと呼ばれる) parse マクロ展開←この処理はソースコードの自動生成といっしょ evaluate 5