50 万行オーダーのプロジェクトを俺 Lisp で書く
でかいことを掲げたわけなのですが、どこの馬の骨ともわからないようなやつが言っても説得力0なので、まずは自己紹介からさせていただきます。 今回、スライドが 76 ページあるので、かなり駆け足で行きますね。スライドは Web からダウンロードできるようにしますので、お話だけ集中して聴いてください。尻切れトンボになるかもしれませんが、これを聞き終わったら、きっとあなたもプロジェクトに Lisp が使いたくなって、 L4u が使いたくなるかもしれません。
プロフィール mitamex こと日向野保夫と申します。 10年前にゼンリン電子地図帳 Zi を開発 Zi8 まで Web 系 GIS とか地図系のプログラムを多く作る。 株式会社匠技研所属 http://www.takugi.com ドコモ標準バンドルのゼンリン地図+ナビの開発に携わる。
WWW,Mail http://d.hatena.ne.jp/mitamex4u/ higano  あっとまーく  takugi.com mitamex4u  あっとまーく  gmail.com
ゼンリン電子地図帳 Zi 開発期間6ヶ月 C++( 一部アセンブラ ) で 25 万行のコード 全体で 45 万行ぐらい 主要な開発は2人
ゼンリン地図+ナビ スザンヌのやつです ドコモの携帯に標準バンドルされています Java で 10 万行ぐらい スクリプト、サーバーサイドのプログラムいっぱい 全体だと 100 万行超える 開発者いっぱい
10 年の月日が流れ 個人 ターゲット上で開発 C++/ アセンブラ 仮想メモリ チーム エミュレーターで開発 Java/ スクリプト /CGI 厳しいメモリー制限
プロジェクトを楽にしたい! つらい思いはしたくない!
目的はプロジェクトの成功! Lisp を使いたいからじゃない。 楽をしたいから Lisp を使う。 Lisp に不得意な部分は無理せずにホスト言語( Java 等)で記述する。 とにかく動くものを早く作りたい。 動くものを見るとお客さんは安心します。
実際問題として Lisp しか選択肢がなかった 小さくて高速なコア 携帯の限られたリソース 携帯上でコンパイルができ、 REPL が動く。
チーム開発では 一人で作っているならどんな言語を使おうがかまわない チームで作るなら、チームのみなさんに Lisp を使っていただかなくてはならない 。 拒絶反応を示す人は絶対にいる。 Lisp は Algol 系の言語を使ってきたプログラマーにはあまりにも敷居が高い。 それでもプロジェクトは待ってくれない。 チームの全員を戦力にできるような作戦が必要。 目的は Lisp を使うことではなく、プロジェクトを成功させること!
L4u Lisp for you! Lisp 大好きっ子が進めたプロジェクトではない 必要の中から生まれた チームによる大規模開発に使える Lisp 携帯からサーバーまでカバーするスケーラビリティ 携帯上でデバッグ、リモートデバッグ可能 超並列型 プロトタイプ  ->  最適化
L4u 誕生の経緯 905 で使っていたスクリプトの問題点を解決したかった。 携帯で Erlang を動かしたかった。 Wikipedia に載っている全言語+いっぱい調査。先祖帰りして Lisp にたどりつく。 その結果、 Lisp でいいじゃん、という結論に至る。 学術的興味ではなく、プロジェクトを進めるための必要性の中から生まれた実用的な言語。
L4u の特徴 携帯からサーバーまでカバーしうる スケーラビリティ 。 S 式のパワーそのままに、人間にやさしい構文 Ruby みたいな 普通の言語っぽい見た目 の Lisp Erlang みたいな 超並列型 Erlang より並列化しやすいよ ホスト言語との連携を前提 とした自己主張しない言語。 glue 言語
プロトタイプから最適化 L4u だけでは速度に限界 実行するだけで各関数の呼び出し回数・実行時間がわかる プロファイラー装備 高速化が必要な部分は L4u ->ホスト言語 2バージョン同時実行によるデバッグ 関数型だからできる
超並列型はチーム開発に向いている Erlang のような超並列型 = アクター クライアント / サーバーと同じような感覚 開発を切り分けしやすい
実行速度、メモリーや コードサイズは? L4u は圧縮して 100KiB ぐらい DoJa では 1MiB までしかコードを入れられない S 式に統一することで、 XML デコーダー等が不要になり、 全体ではコードサイズが減少 継続・超並列型により、苦労して作っていた部分が平易なコードで作れてサイズ減少 905 のスクリプトより2ケタ高速。メモリー使用量も大幅に減少。
現在動作しているプラットフォーム DoJa MIDP  などの携帯電話プラットフォーム 3 つのプロジェクトに L4u を使っています Linux,Windows の Java 環境 サーバーサイドを L4u で書いています ツールを書いて使ってます Windows の .NET framework Managed C++,C# と連携して、 OpenGL や DirectX も使用可能。 AR とかやってます
みんなに使ってもらうために エディタも作りました JE  という PureJava のエディタを改造 L4u の普通の言語っぽい構文に対応。 メッセージ通信で他のプロセスと連携 誰か Eclipse で作ってくれ! 名前は Eclisp でお願いします。
2009 年オープンソースで公開予定 開発者募集中! Objective-C 版がほしいよ 使いたい人は連絡ください mitamex4u  あっとまーく  gmail.com higano  あっとまーく  takugi.com
まずは S 式
tuple を導入 タプルは評価してもそれ自体を返す List みたいなもの {a b}  (tuple a b) '{a b} (tuple 'a 'b)  タプルですか?  (tuple? {1 2}) SXML より直観的にわかりやすくなる。 SXML 版 (html (body ( @  (bgcolor 0xff0000)) " はろー " L4u SXML 版 (html (body  { bgcolor 0xff0000 }  " はろー "
XHTML <body bgcolor=&quot;#ffff00&quot; text=&quot;#000000&quot; link=&quot;#ff0000&quot;> 「タイトル :1 」 「タイトル : <b>b ボールド 2</b> 」 「タイトル :<strong>strong ボールド 3</strong> 」 <hr size=5 noshade /> 「タイトル :<i>i イタリック 1</i> 」 「タイトル :<em>em イタリック 2</em> 」 <br /> 「タイトル :<b><i>b+i ボールド + イタリック </i></b> 」 <br /> <img src=&quot;p32.gif&quot; id=&quot;p320&quot; /> <dl> <dt>HTML <dd>HyperText Markup Language  の略で・・・ </dd> </dt> <dt>WWW <dd>World Wide Web  の略で・・・ </dd> </dt> </dl> </body>
tuple を使うと・・ L4u SXML (body {bgcolor &quot;#ffff00&quot; } {text &quot;#000000&quot; } {link &quot;#ff0000&quot;} &quot; 「タイトル :1 」 &quot; &quot; 「タイトル :&quot; (b &quot;b ボールド 2&quot;) &quot; 」 &quot; &quot; 「タイトル :&quot; (strong &quot;strong ボールド 3&quot;)  &quot; 」 &quot; (hr {size &quot;5&quot;} {noshade}) &quot; 「タイトル :&quot; (i &quot;i イタリック 1&quot;) &quot; 」 &quot; &quot; 「タイトル :&quot; (em &quot;em イタリック 2&quot;) &quot; 」 &quot; (br) &quot; 「タイトル :&quot; (b (i &quot;b+i ボールド + イタリック &quot;)) &quot; 」 &quot; (br) (img {src &quot;p32.gif&quot;} {id &quot;p320&quot;}) (dl (dt &quot;HTML&quot; (dd &quot;HyperText Markup Language  の略で・・・ &quot;) ) (dt &quot;WWW&quot; (dd &quot;World Wide Web  の略で・・・ &quot;) ) ) )
まずは JSON で開発してもらって・・ JSON は標準でライブラリーも用意されているようなフォーマット。導入に障壁が少ない。 配列にデータを用意し、関数で JSON に変換するだけ。お手軽に扱える。 S 式で出力してください。    ( ゚ Д ゚ ) ハァ ? JSON で出力してください。  (・∀・)イイ !!
まずは JSON で開発してもらって・・ 後で S 式に置き換える。 JSON で完璧に動くものを作り、 JSON への変換部分を S 式に変換する関数に置き換える 。 JSON で出力できるように作ってくれ、とお願いするだけでいつの間にか S 式を出力してくれるサーバーの出来上がり。
JSON で作っていたつもりが・・・ { &quot;Person&quot; : { &quot;name&quot; : &quot;Yasuo Higano&quot;, &quot;nickname&quot; : &quot;mitamex&quot;, &quot;interest&quot; : [ { &quot;title&quot; : &quot;SETI@home&quot;, &quot;url&quot; : &quot;http://setiathome.ssl.berkeley.edu/&quot; }, { &quot;title&quot; : &quot;Flickr&quot;, &quot;url&quot; : &quot;http://www.flickr.com/&quot; } ] } }
JSON で作っていたつもりが・・・ いつの間にか S 式でやり取りされてる! ( { Person ( { name &quot;Yasuo Higano&quot; } { interest &quot;mitamex&quot; } { interest ( ( { title &quot;SETI@home&quot; } { url &quot;http://setiathome.ssl.berkeley.edu/&quot; } ) ( { title &quot;Flickr&quot; } { url &quot;http://www.flickr.com/&quot; } ) ) } ) } )
まとめ それとは気がつかないうちに、データを S 式でやりとりさせましょう
どこでも REPL
携帯電話上でデバッグ可能 エミュレーターで動いているのに実機では動かないことがある! 問題が起きている実機で直接デバッグしたら原因がすぐわかるのに! デザイナーから1ドット右、1ドット上!とか言われてもその場で修正。
携帯電話にリモートデバッグ Doja はソケットが使えないので WebServer にポーリングで HttpGet してコマンドを受け取る。 PC 側は WebServer と S 式メッセージでやりとり。 携帯  <-> WebServer <-> PC ちょっともっさりしているけど、実用上問題なし。
サーバーサイド L4u
携帯でもサーバーでも同じ言語が動く 携帯で重い処理はサーバーに移す 通信なしでレスポンスを早くしたければ携帯に移す
smarty もどき 正規表現を使用せず、約 60 行のソースで、次のような L4u のコードが混在した html を処理可能 <html> <head> <title><%= title %></title> </head> <body> test of foreach<br> <% foreach data (x) do %> データは <%= x %><br> <% end %> test of repeat<br> <% repeat 10 (x) do %> カウント <%= x %> 番目でーす <br> <% end %> </body> </html>
変換された l4u のコードを eval するだけ (println &quot;<html><head><title>&quot;) (println title ) (println &quot;</title></head><body>test of foreach<br>&quot;) foreach data (x) do  (println &quot; データは &quot;) (println  x ) (println &quot;<br>&quot;) end  (println &quot;test of repeat<br>&quot;) repeat 10 (x) do  (println &quot; カウント &quot;) (println  x ) (println &quot; 番目でーす <br>&quot;) end  (println &quot;</body></html>&quot;)
ホスト言語との連携
ホスト言語との連携を前提にする L4u は自己主張しません。 L4u で全部書けとか言いません。 L4u が苦手な部分はホスト言語に任せてしまえば良い。 実行するだけでプロファイリング完了。 これで遅い部分をホスト言語に置き換えればよい。 極限までスピードに最適化した L4u のプログラムはメッセージキューとタスクマネージャ以外すべてホスト言語に置き換わる。
reflection が使えれば var obj = (create &quot;System.Windows.Forms.MessageBox) ( obj.Show  &quot;Hello World!&quot;) CLOS のように (Show obj “Hello World!”)  と書いてもよい。 Objective-C のように [obj Show “Hello World”] とも書けます。
Integer クラスの実装 その1 public class L4uObjInteger extends L4uObj implements IL4uEmbdFunc { public int _val; static L4uEnvironment _exe; public final L4uEnvironment GetExecUnit() { return _exe; } //  実行ユニットが対象としているクラスの実装クラス public final Object GetClassObj() { return _exe._funenv._cls; }
Integer クラスの実装 その2 public static final void InitImplementation() { L4uObjInteger obj = new L4uObjInteger(0); _exe = InitEmbd(&quot;L4uObjInteger&quot;,obj); RegFunc(_exe, new L4uVMFuncEmbd(&quot;inc!&quot;, 1) { public L4uObj exec(L4uVMExecFun exe, int num_params) { _Stack s = exe._vmthread._stack; L4uObjInteger obj = ((L4uObjInteger) s.at(0)); obj._val++; return obj; } }); 無名インナークラスを使って楽チンに実装
delegate/cc call/cc はオーバーヘッドが大きい delegate/cc は呼び出した時点で処理が停止し、明示的に“継続”されるまで実行されない。 スタックをそのままにしておくだけ。スタックのコピーを作る必要がない。 == オーバーヘッドがない。 ホスト言語に後のことはまかせた!
delegate/cc の例 doja で IME を使って文字を入力 ; L4u var result = (delegate/cc (lambda (cont) (IMEGetText cont &quot; はろー &quot;))) (println result) // Java static L4uContinuation _ime_cont; RegFunc( new L4uVMFuncEmbd(&quot;IMEGetText&quot;,2){ public Object Exec(L4uVMExecFun exe,int num_params){ _ime_cont = (L4uContinuation )exe._vmthread._stack.at(0) ); imeOn(&quot;&quot;+ exe._vmthread._stack.at(1),  TextBox.DISPLAY_ANY, TextBox.ALPHA) } } ) void processIMEEvent(int type, String text)  { _ime_cont.do_continue(text); }
プリプロセッサ、マクロ
L4u のソースコード処理の流れ プリプロセッサ処理 ↓ シンボル化 ↓ L4u によるシンボル変換 ↓ Lisp 的なマクロ適用
C 言語みたいなプリプロセッサ 同じシリーズの携帯電話でもコードを分ける必要あり。 言語仕様としてプリプロセッサをサポートしないと、 Java に外部プログラムでプリプロセッサを適用するような混乱が起きてしまう! 美しくない? うるせー!  必要なんだ!
プリプロセッサの例 プリプロセッサは独自の環境で動く L4u <#define DEV 'N907 #> <#define VER 105 #> <#if (and (eq? DEV 'N907) (> VER 100))) #> S 式 <#else#> S 式 <#end#>
もはや S 式じゃない? マクロより凶悪な S 式いじり マクロよりもプログラマブルな L4u で記述されたマクロ(のようなもの) シンボル化されたソースを直接いじくって、かっこの外に飛び出せ! ;  かっこの外にある class  というシンボルの処理 switch sym case 'class var a = (read) var b = (read) var c = (readListUntil 'end) var lb = (new ListBuilder) (lb.add! 'class) (lb.add! a) (lb.add! b) (lb.addList! c) (lb.toList)
もはや S 式じゃない? マクロより凶悪な S 式いじり class  クラス名 ( 継承するクラス ) 定義 end ↓ (class  クラス名 継承するクラス 定義 ) に変換される。
Dylan みたいだけど S 式を捨てたわけじゃない どんな構文でも、 最終的に S 式に変換 される。 だから糖衣構文なしで直接 S 式で書いてもよい。 マクロは、変換後の S 式に対して適用される。
L4u は超並列指向
L4u の超並列指向 Erlang と同じものを目指している もともと Erlang を携帯で動かしたかった。 Erlang と同じメッセージパッシング。 同一プロセスはもちろん、他プロセス、ネットワーク越しの PC とも通信可能。 共有メモリは一切使えない。メモリーの排他機能は持たない。 Erlang と同じく、言語が処理するライトウェイトスレッドと、 OS がサポートするスレッドのハイブリッド構成。
メッセージパッシングでの並列処理を前提で考えるといろいろ楽ちん GPS 、 IO 、描画、 UI 、入力・・・ 非同期だらけ。 メッセージパッシングはクライアント / サーバーのような形式。チーム開発にもぴったり。
簡単な並列化 フィボナッチ数 オリジナル defun fib(n) if(<= n 2) then 1 else (+ (fib (- n 1)) (fib (- n 2))) end end
簡単な並列化 フィボナッチ数 計算部分を並列化 defun fib(n) if(<= n 2) then 1 else var {a b} = ( parallel (fib (- n 1)) (fib (- n 2)) ) (+ a b) end end
他のプロセスにメッセージを送る defun remoteRPL(name url port) var target = (new RemotePID name url port) loop (print &quot;remoteL4u>&quot;) var str = (readln) ( target.send  {‘print str}) (println &quot;&quot;) end end (remoteRPL “mymsgloop” “localhost” 8080)
他のプロセスからの メッセージを受ける defun messageLoop(s) (println s) loop switch  (receive) match {'print msg} (println “ メッセージは”  msg) match msg (println “ なんかわかんないけど”  msg) end end end home>l4u port:8080 l4u>(spawn “mymsgloop” messageLoop “hello”)
L4u は人にやさしい Lisp を 目指した構文 心理学とか脳生理学にに凝っている男が作った Lisp
例えば… 脳のローレベル部分は論理で動いていない あなたのことは嫌いではない あなたのことが好きだ 論理的には同じことを言っているが、 二重否定では“嫌い”という意味を右脳がダイレクトに感じ、それを左脳が論理的に考えて好きだと理解する。 “ 好きだ”は、右脳も左脳も同じ意味を考えなくても直観的に理解できる。
人にやさしい構文とは Lisp は人間にやさしくない コンピューターにやさしい言語。 Algol 系言語から入った人は、カッコだらけで生理的な嫌悪感を抱く! 特殊形式も関数も同じ書き方だから知識なしには理解できない。 Lisp の特徴を生かしつつ人にやさしい構文にしたい。
日本語が使える 内部は UNICODE 文字は文字。何バイトとか関係ない。 長さを調べたら文字数が返る バイトの長さを調べたかったら、バイト列に変換してから 変数や関数名に日本語が使えます
右脳で直感的に理解できる構文 例えば  if (if a b c) って Lisp の知識がない人には何をやるのかさっぱりわからん。 コンピューターにとっては冗長で無駄な情報。でも、人間には理解を助けるためのアンカーが必要。 if a then b else c end then,else はコンピューターにとっては邪魔な記号だが、人間はこれを見たらどの部分が何を意味しているかすぐわかる。 これだったらプログラミングをかじった人間のほとんどが理解できるはず。
やりたいことを明示する continue,break,return を持つ ありがちな会話 初心者「 scheme で break ってどうやるんですか?」 プロ「継続でできるよ」 初心者「で、どうやってやるんじゃい!」 実際にやりたいことは継続ではない continue したい。 break したい。 return したいだけなのに、なんで継続使わなくちゃいけないの?
冗長でも、 やりたいことを明示するをもつ loop,while などのブロック構造 そりゃなんでも再帰で書けるけどさ・・ 本当にやりたいのは再帰じゃなくてループだろ? 関数は defun(def) で定義。変数は var で定義。 互換性のために scheme みたいに define も OK
loop の例 let c = 0 in loop when(>= c 10) do break (* c 2) end set! c = (+ c 1) end end
repeat の例 repeat 10 from 5 (x) do (println x) when (== x 10) do break 'ok end end
見た目は Algol 系でも 最終的には S 式で処理される repeat 10 from 0 (x) do (println x) end ↓ ( let ( ( x 0 ) ) ( while-f ( < x ( + 10 0 ) ) ( println x ) ( objpath:x.inc! ) ) ) マクロは変換後の S 式に対して適用される。
かっこを減らせ! その 1 ひとつ前の処理の戻り値を指す  it  を追加。 (print (fizzbuzz (seq 1 100))) ↓ (seq 1 100)  (fizzbuzz it) (print it)
かっこを減らせ! その 2 ->  演算子を追加。 戻り値を次の関数の第一引数に放り込める。 処理の流れが左から右になる。 処理のパイプラインを簡単に作れる。 (print (fizzbuzz (seq 1 100))) ↓ (seq 1 100) -> (fizzbuzz) -> (print)
第一引数を特別扱い L4u ではすべてがオブジェクト (+ 1 2 3)  は整数の加算が呼ばれるべき (+ “abc” “def”)  は文字列の結合が呼ばれるべき どのクラスのメソッドを呼び出すか識別するために、第一引数を使う クラスごとにメソッドを定義するだけで、第一引数で識別する多重ディスパッチになる
高階関数の引数の順番が逆 map はリストを貰って、リストを返す。だからリストが一番重要な引数のはず。 scheme:  (map function list) ↓ l4u:  (map list function) この引数の順番だから、 (map list function) -> (map list function)  という風に処理をパイプライン化しやすい。
関数呼び出しの優先順位 変数スコープにある関数 多重ディスパッチを登録しておけば、 CLOS と同じように処理される。 第一引数のクラスに属する関数 多重ディスパッチで処理されなければ、 Java,Ruby のようにクラスのメソッドで処理される。
非 CLOS なオブジェクトシステム Java ・ Ruby のようなクラス class Animal() def  鳴く () end end class  犬 (Animal) def  鳴く () (println “ わんわんお!” ) end def  お手 () (println “ あいよ“ ) end end var dog = ( 犬 .new) ; var dog = (new  犬 )  どっちでもいいよ (dog. 鳴く ) ; ( 鳴く  dog)  どっちでもいいよ [dog  お手 ] ; Objective-C のメッセージ式と同じ
非 CLOS なオブジェクトシステム class  住所録 () var  名前  = “” var  住所  = “” var  電話番号  = “” def construct( 名前 住所 電話番号 ) set! self. 名前  =  名前 set! self. 住所  =  住所 set! self. 電話番号  =  電話番号 end def dump() (println  名前 “  : “  住所 “  : “  電話番号 ) end end var obj = (new  住所録 “ mitamex” “ 千葉県” “ 090-xxxx-xxxx”)
SLOT じゃなければ、コピペで抜き出して簡単にテストできるよ var  名前  = “” var  住所  = “” var  電話番号  = “” def construct( 名前 住所 電話番号 ) set! self. 名前  =  名前 set! self. 住所  =  住所 set! self. 電話番号  =  電話番号 end def dump() (println  名前 “  : “  住所 “  : “  電話番号 ) end L4u>set!  名前  = “ 阿部高和” L4u>(dump)
なぜ CLOS があるのに Java っぽいクラスを使うか ホスト言語が Java だから。 L4u の遅い部分はホスト言語で書きなおすので、同じ様な形が好ましい。 ホスト言語のオブジェクトを簡単に呼び出せるので、ホスト言語と同じ形のオブジェクトにしたかった。 var msgbox = (create &quot;System.windows.forms.MessageBox”) (msgbox.show &quot;Hello world&quot;)
まとめ 楽するために L4u を使おう! どこでも REPL プロトタイプ作成ー>ボトルネックをホスト言語で最適化 超並列型 Algol 系プログラマでもとっつきやすい構文 携帯電話でも動く小さなコア 携帯電話からサーバーまでカバーするスケーラビリティ
ありがとうございました 開発者募集中! 2009 年オープンソースで登場予定

2008.10.18 L4u Tech Talk

  • 1.
  • 2.
    でかいことを掲げたわけなのですが、どこの馬の骨ともわからないようなやつが言っても説得力0なので、まずは自己紹介からさせていただきます。 今回、スライドが 76ページあるので、かなり駆け足で行きますね。スライドは Web からダウンロードできるようにしますので、お話だけ集中して聴いてください。尻切れトンボになるかもしれませんが、これを聞き終わったら、きっとあなたもプロジェクトに Lisp が使いたくなって、 L4u が使いたくなるかもしれません。
  • 3.
    プロフィール mitamex こと日向野保夫と申します。10年前にゼンリン電子地図帳 Zi を開発 Zi8 まで Web 系 GIS とか地図系のプログラムを多く作る。 株式会社匠技研所属 http://www.takugi.com ドコモ標準バンドルのゼンリン地図+ナビの開発に携わる。
  • 4.
    WWW,Mail http://d.hatena.ne.jp/mitamex4u/ higano あっとまーく  takugi.com mitamex4u  あっとまーく  gmail.com
  • 5.
    ゼンリン電子地図帳 Zi 開発期間6ヶ月C++( 一部アセンブラ ) で 25 万行のコード 全体で 45 万行ぐらい 主要な開発は2人
  • 6.
    ゼンリン地図+ナビ スザンヌのやつです ドコモの携帯に標準バンドルされていますJava で 10 万行ぐらい スクリプト、サーバーサイドのプログラムいっぱい 全体だと 100 万行超える 開発者いっぱい
  • 7.
    10 年の月日が流れ 個人ターゲット上で開発 C++/ アセンブラ 仮想メモリ チーム エミュレーターで開発 Java/ スクリプト /CGI 厳しいメモリー制限
  • 8.
  • 9.
    目的はプロジェクトの成功! Lisp を使いたいからじゃない。楽をしたいから Lisp を使う。 Lisp に不得意な部分は無理せずにホスト言語( Java 等)で記述する。 とにかく動くものを早く作りたい。 動くものを見るとお客さんは安心します。
  • 10.
    実際問題として Lisp しか選択肢がなかった小さくて高速なコア 携帯の限られたリソース 携帯上でコンパイルができ、 REPL が動く。
  • 11.
    チーム開発では 一人で作っているならどんな言語を使おうがかまわない チームで作るなら、チームのみなさんにLisp を使っていただかなくてはならない 。 拒絶反応を示す人は絶対にいる。 Lisp は Algol 系の言語を使ってきたプログラマーにはあまりにも敷居が高い。 それでもプロジェクトは待ってくれない。 チームの全員を戦力にできるような作戦が必要。 目的は Lisp を使うことではなく、プロジェクトを成功させること!
  • 12.
    L4u Lisp foryou! Lisp 大好きっ子が進めたプロジェクトではない 必要の中から生まれた チームによる大規模開発に使える Lisp 携帯からサーバーまでカバーするスケーラビリティ 携帯上でデバッグ、リモートデバッグ可能 超並列型 プロトタイプ -> 最適化
  • 13.
    L4u 誕生の経緯 905で使っていたスクリプトの問題点を解決したかった。 携帯で Erlang を動かしたかった。 Wikipedia に載っている全言語+いっぱい調査。先祖帰りして Lisp にたどりつく。 その結果、 Lisp でいいじゃん、という結論に至る。 学術的興味ではなく、プロジェクトを進めるための必要性の中から生まれた実用的な言語。
  • 14.
    L4u の特徴 携帯からサーバーまでカバーしうるスケーラビリティ 。 S 式のパワーそのままに、人間にやさしい構文 Ruby みたいな 普通の言語っぽい見た目 の Lisp Erlang みたいな 超並列型 Erlang より並列化しやすいよ ホスト言語との連携を前提 とした自己主張しない言語。 glue 言語
  • 15.
    プロトタイプから最適化 L4u だけでは速度に限界実行するだけで各関数の呼び出し回数・実行時間がわかる プロファイラー装備 高速化が必要な部分は L4u ->ホスト言語 2バージョン同時実行によるデバッグ 関数型だからできる
  • 16.
    超並列型はチーム開発に向いている Erlang のような超並列型 = アクタークライアント / サーバーと同じような感覚 開発を切り分けしやすい
  • 17.
    実行速度、メモリーや コードサイズは? L4uは圧縮して 100KiB ぐらい DoJa では 1MiB までしかコードを入れられない S 式に統一することで、 XML デコーダー等が不要になり、 全体ではコードサイズが減少 継続・超並列型により、苦労して作っていた部分が平易なコードで作れてサイズ減少 905 のスクリプトより2ケタ高速。メモリー使用量も大幅に減少。
  • 18.
    現在動作しているプラットフォーム DoJa MIDP などの携帯電話プラットフォーム 3 つのプロジェクトに L4u を使っています Linux,Windows の Java 環境 サーバーサイドを L4u で書いています ツールを書いて使ってます Windows の .NET framework Managed C++,C# と連携して、 OpenGL や DirectX も使用可能。 AR とかやってます
  • 19.
    みんなに使ってもらうために エディタも作りました JE という PureJava のエディタを改造 L4u の普通の言語っぽい構文に対応。 メッセージ通信で他のプロセスと連携 誰か Eclipse で作ってくれ! 名前は Eclisp でお願いします。
  • 20.
    2009 年オープンソースで公開予定 開発者募集中!Objective-C 版がほしいよ 使いたい人は連絡ください mitamex4u  あっとまーく  gmail.com higano  あっとまーく  takugi.com
  • 21.
  • 22.
    tuple を導入 タプルは評価してもそれ自体を返すList みたいなもの {a b} (tuple a b) '{a b} (tuple 'a 'b) タプルですか?  (tuple? {1 2}) SXML より直観的にわかりやすくなる。 SXML 版 (html (body ( @ (bgcolor 0xff0000)) &quot; はろー &quot; L4u SXML 版 (html (body { bgcolor 0xff0000 } &quot; はろー &quot;
  • 23.
    XHTML <body bgcolor=&quot;#ffff00&quot;text=&quot;#000000&quot; link=&quot;#ff0000&quot;> 「タイトル :1 」 「タイトル : <b>b ボールド 2</b> 」 「タイトル :<strong>strong ボールド 3</strong> 」 <hr size=5 noshade /> 「タイトル :<i>i イタリック 1</i> 」 「タイトル :<em>em イタリック 2</em> 」 <br /> 「タイトル :<b><i>b+i ボールド + イタリック </i></b> 」 <br /> <img src=&quot;p32.gif&quot; id=&quot;p320&quot; /> <dl> <dt>HTML <dd>HyperText Markup Language の略で・・・ </dd> </dt> <dt>WWW <dd>World Wide Web の略で・・・ </dd> </dt> </dl> </body>
  • 24.
    tuple を使うと・・ L4uSXML (body {bgcolor &quot;#ffff00&quot; } {text &quot;#000000&quot; } {link &quot;#ff0000&quot;} &quot; 「タイトル :1 」 &quot; &quot; 「タイトル :&quot; (b &quot;b ボールド 2&quot;) &quot; 」 &quot; &quot; 「タイトル :&quot; (strong &quot;strong ボールド 3&quot;) &quot; 」 &quot; (hr {size &quot;5&quot;} {noshade}) &quot; 「タイトル :&quot; (i &quot;i イタリック 1&quot;) &quot; 」 &quot; &quot; 「タイトル :&quot; (em &quot;em イタリック 2&quot;) &quot; 」 &quot; (br) &quot; 「タイトル :&quot; (b (i &quot;b+i ボールド + イタリック &quot;)) &quot; 」 &quot; (br) (img {src &quot;p32.gif&quot;} {id &quot;p320&quot;}) (dl (dt &quot;HTML&quot; (dd &quot;HyperText Markup Language の略で・・・ &quot;) ) (dt &quot;WWW&quot; (dd &quot;World Wide Web の略で・・・ &quot;) ) ) )
  • 25.
    まずは JSON で開発してもらって・・JSON は標準でライブラリーも用意されているようなフォーマット。導入に障壁が少ない。 配列にデータを用意し、関数で JSON に変換するだけ。お手軽に扱える。 S 式で出力してください。  ( ゚ Д ゚ ) ハァ ? JSON で出力してください。  (・∀・)イイ !!
  • 26.
    まずは JSON で開発してもらって・・後で S 式に置き換える。 JSON で完璧に動くものを作り、 JSON への変換部分を S 式に変換する関数に置き換える 。 JSON で出力できるように作ってくれ、とお願いするだけでいつの間にか S 式を出力してくれるサーバーの出来上がり。
  • 27.
    JSON で作っていたつもりが・・・ {&quot;Person&quot; : { &quot;name&quot; : &quot;Yasuo Higano&quot;, &quot;nickname&quot; : &quot;mitamex&quot;, &quot;interest&quot; : [ { &quot;title&quot; : &quot;SETI@home&quot;, &quot;url&quot; : &quot;http://setiathome.ssl.berkeley.edu/&quot; }, { &quot;title&quot; : &quot;Flickr&quot;, &quot;url&quot; : &quot;http://www.flickr.com/&quot; } ] } }
  • 28.
    JSON で作っていたつもりが・・・ いつの間にかS 式でやり取りされてる! ( { Person ( { name &quot;Yasuo Higano&quot; } { interest &quot;mitamex&quot; } { interest ( ( { title &quot;SETI@home&quot; } { url &quot;http://setiathome.ssl.berkeley.edu/&quot; } ) ( { title &quot;Flickr&quot; } { url &quot;http://www.flickr.com/&quot; } ) ) } ) } )
  • 29.
  • 30.
  • 31.
  • 32.
    携帯電話にリモートデバッグ Doja はソケットが使えないのでWebServer にポーリングで HttpGet してコマンドを受け取る。 PC 側は WebServer と S 式メッセージでやりとり。 携帯 <-> WebServer <-> PC ちょっともっさりしているけど、実用上問題なし。
  • 33.
  • 34.
  • 35.
    smarty もどき 正規表現を使用せず、約60 行のソースで、次のような L4u のコードが混在した html を処理可能 <html> <head> <title><%= title %></title> </head> <body> test of foreach<br> <% foreach data (x) do %> データは <%= x %><br> <% end %> test of repeat<br> <% repeat 10 (x) do %> カウント <%= x %> 番目でーす <br> <% end %> </body> </html>
  • 36.
    変換された l4u のコードをeval するだけ (println &quot;<html><head><title>&quot;) (println title ) (println &quot;</title></head><body>test of foreach<br>&quot;) foreach data (x) do (println &quot; データは &quot;) (println x ) (println &quot;<br>&quot;) end (println &quot;test of repeat<br>&quot;) repeat 10 (x) do (println &quot; カウント &quot;) (println x ) (println &quot; 番目でーす <br>&quot;) end (println &quot;</body></html>&quot;)
  • 37.
  • 38.
    ホスト言語との連携を前提にする L4u は自己主張しません。L4u で全部書けとか言いません。 L4u が苦手な部分はホスト言語に任せてしまえば良い。 実行するだけでプロファイリング完了。 これで遅い部分をホスト言語に置き換えればよい。 極限までスピードに最適化した L4u のプログラムはメッセージキューとタスクマネージャ以外すべてホスト言語に置き換わる。
  • 39.
    reflection が使えれば varobj = (create &quot;System.Windows.Forms.MessageBox) ( obj.Show &quot;Hello World!&quot;) CLOS のように (Show obj “Hello World!”)  と書いてもよい。 Objective-C のように [obj Show “Hello World”] とも書けます。
  • 40.
    Integer クラスの実装 その1 publicclass L4uObjInteger extends L4uObj implements IL4uEmbdFunc { public int _val; static L4uEnvironment _exe; public final L4uEnvironment GetExecUnit() { return _exe; } // 実行ユニットが対象としているクラスの実装クラス public final Object GetClassObj() { return _exe._funenv._cls; }
  • 41.
    Integer クラスの実装 その2 publicstatic final void InitImplementation() { L4uObjInteger obj = new L4uObjInteger(0); _exe = InitEmbd(&quot;L4uObjInteger&quot;,obj); RegFunc(_exe, new L4uVMFuncEmbd(&quot;inc!&quot;, 1) { public L4uObj exec(L4uVMExecFun exe, int num_params) { _Stack s = exe._vmthread._stack; L4uObjInteger obj = ((L4uObjInteger) s.at(0)); obj._val++; return obj; } }); 無名インナークラスを使って楽チンに実装
  • 42.
    delegate/cc call/cc はオーバーヘッドが大きいdelegate/cc は呼び出した時点で処理が停止し、明示的に“継続”されるまで実行されない。 スタックをそのままにしておくだけ。スタックのコピーを作る必要がない。 == オーバーヘッドがない。 ホスト言語に後のことはまかせた!
  • 43.
    delegate/cc の例 dojaで IME を使って文字を入力 ; L4u var result = (delegate/cc (lambda (cont) (IMEGetText cont &quot; はろー &quot;))) (println result) // Java static L4uContinuation _ime_cont; RegFunc( new L4uVMFuncEmbd(&quot;IMEGetText&quot;,2){ public Object Exec(L4uVMExecFun exe,int num_params){ _ime_cont = (L4uContinuation )exe._vmthread._stack.at(0) ); imeOn(&quot;&quot;+ exe._vmthread._stack.at(1), TextBox.DISPLAY_ANY, TextBox.ALPHA) } } ) void processIMEEvent(int type, String text) { _ime_cont.do_continue(text); }
  • 44.
  • 45.
    L4u のソースコード処理の流れ プリプロセッサ処理↓ シンボル化 ↓ L4u によるシンボル変換 ↓ Lisp 的なマクロ適用
  • 46.
    C 言語みたいなプリプロセッサ 同じシリーズの携帯電話でもコードを分ける必要あり。言語仕様としてプリプロセッサをサポートしないと、 Java に外部プログラムでプリプロセッサを適用するような混乱が起きてしまう! 美しくない? うるせー!  必要なんだ!
  • 47.
    プリプロセッサの例 プリプロセッサは独自の環境で動く L4u<#define DEV 'N907 #> <#define VER 105 #> <#if (and (eq? DEV 'N907) (> VER 100))) #> S 式 <#else#> S 式 <#end#>
  • 48.
    もはや S 式じゃない?マクロより凶悪な S 式いじり マクロよりもプログラマブルな L4u で記述されたマクロ(のようなもの) シンボル化されたソースを直接いじくって、かっこの外に飛び出せ! ; かっこの外にある class  というシンボルの処理 switch sym case 'class var a = (read) var b = (read) var c = (readListUntil 'end) var lb = (new ListBuilder) (lb.add! 'class) (lb.add! a) (lb.add! b) (lb.addList! c) (lb.toList)
  • 49.
    もはや S 式じゃない?マクロより凶悪な S 式いじり class クラス名 ( 継承するクラス ) 定義 end ↓ (class クラス名 継承するクラス 定義 ) に変換される。
  • 50.
    Dylan みたいだけど S式を捨てたわけじゃない どんな構文でも、 最終的に S 式に変換 される。 だから糖衣構文なしで直接 S 式で書いてもよい。 マクロは、変換後の S 式に対して適用される。
  • 51.
  • 52.
    L4u の超並列指向 Erlangと同じものを目指している もともと Erlang を携帯で動かしたかった。 Erlang と同じメッセージパッシング。 同一プロセスはもちろん、他プロセス、ネットワーク越しの PC とも通信可能。 共有メモリは一切使えない。メモリーの排他機能は持たない。 Erlang と同じく、言語が処理するライトウェイトスレッドと、 OS がサポートするスレッドのハイブリッド構成。
  • 53.
    メッセージパッシングでの並列処理を前提で考えるといろいろ楽ちん GPS 、IO 、描画、 UI 、入力・・・ 非同期だらけ。 メッセージパッシングはクライアント / サーバーのような形式。チーム開発にもぴったり。
  • 54.
    簡単な並列化 フィボナッチ数 オリジナル defunfib(n) if(<= n 2) then 1 else (+ (fib (- n 1)) (fib (- n 2))) end end
  • 55.
    簡単な並列化 フィボナッチ数 計算部分を並列化 defunfib(n) if(<= n 2) then 1 else var {a b} = ( parallel (fib (- n 1)) (fib (- n 2)) ) (+ a b) end end
  • 56.
    他のプロセスにメッセージを送る defun remoteRPL(nameurl port) var target = (new RemotePID name url port) loop (print &quot;remoteL4u>&quot;) var str = (readln) ( target.send {‘print str}) (println &quot;&quot;) end end (remoteRPL “mymsgloop” “localhost” 8080)
  • 57.
    他のプロセスからの メッセージを受ける defunmessageLoop(s) (println s) loop switch (receive) match {'print msg} (println “ メッセージは” msg) match msg (println “ なんかわかんないけど” msg) end end end home>l4u port:8080 l4u>(spawn “mymsgloop” messageLoop “hello”)
  • 58.
    L4u は人にやさしい Lispを 目指した構文 心理学とか脳生理学にに凝っている男が作った Lisp
  • 59.
    例えば… 脳のローレベル部分は論理で動いていない あなたのことは嫌いではないあなたのことが好きだ 論理的には同じことを言っているが、 二重否定では“嫌い”という意味を右脳がダイレクトに感じ、それを左脳が論理的に考えて好きだと理解する。 “ 好きだ”は、右脳も左脳も同じ意味を考えなくても直観的に理解できる。
  • 60.
    人にやさしい構文とは Lisp は人間にやさしくないコンピューターにやさしい言語。 Algol 系言語から入った人は、カッコだらけで生理的な嫌悪感を抱く! 特殊形式も関数も同じ書き方だから知識なしには理解できない。 Lisp の特徴を生かしつつ人にやさしい構文にしたい。
  • 61.
    日本語が使える 内部は UNICODE文字は文字。何バイトとか関係ない。 長さを調べたら文字数が返る バイトの長さを調べたかったら、バイト列に変換してから 変数や関数名に日本語が使えます
  • 62.
    右脳で直感的に理解できる構文 例えば if (if a b c) って Lisp の知識がない人には何をやるのかさっぱりわからん。 コンピューターにとっては冗長で無駄な情報。でも、人間には理解を助けるためのアンカーが必要。 if a then b else c end then,else はコンピューターにとっては邪魔な記号だが、人間はこれを見たらどの部分が何を意味しているかすぐわかる。 これだったらプログラミングをかじった人間のほとんどが理解できるはず。
  • 63.
    やりたいことを明示する continue,break,return を持つありがちな会話 初心者「 scheme で break ってどうやるんですか?」 プロ「継続でできるよ」 初心者「で、どうやってやるんじゃい!」 実際にやりたいことは継続ではない continue したい。 break したい。 return したいだけなのに、なんで継続使わなくちゃいけないの?
  • 64.
    冗長でも、 やりたいことを明示するをもつ loop,whileなどのブロック構造 そりゃなんでも再帰で書けるけどさ・・ 本当にやりたいのは再帰じゃなくてループだろ? 関数は defun(def) で定義。変数は var で定義。 互換性のために scheme みたいに define も OK
  • 65.
    loop の例 letc = 0 in loop when(>= c 10) do break (* c 2) end set! c = (+ c 1) end end
  • 66.
    repeat の例 repeat10 from 5 (x) do (println x) when (== x 10) do break 'ok end end
  • 67.
    見た目は Algol 系でも最終的には S 式で処理される repeat 10 from 0 (x) do (println x) end ↓ ( let ( ( x 0 ) ) ( while-f ( < x ( + 10 0 ) ) ( println x ) ( objpath:x.inc! ) ) ) マクロは変換後の S 式に対して適用される。
  • 68.
    かっこを減らせ! その 1ひとつ前の処理の戻り値を指す it を追加。 (print (fizzbuzz (seq 1 100))) ↓ (seq 1 100) (fizzbuzz it) (print it)
  • 69.
    かっこを減らせ! その 2-> 演算子を追加。 戻り値を次の関数の第一引数に放り込める。 処理の流れが左から右になる。 処理のパイプラインを簡単に作れる。 (print (fizzbuzz (seq 1 100))) ↓ (seq 1 100) -> (fizzbuzz) -> (print)
  • 70.
    第一引数を特別扱い L4u ではすべてがオブジェクト(+ 1 2 3)  は整数の加算が呼ばれるべき (+ “abc” “def”)  は文字列の結合が呼ばれるべき どのクラスのメソッドを呼び出すか識別するために、第一引数を使う クラスごとにメソッドを定義するだけで、第一引数で識別する多重ディスパッチになる
  • 71.
    高階関数の引数の順番が逆 map はリストを貰って、リストを返す。だからリストが一番重要な引数のはず。scheme: (map function list) ↓ l4u: (map list function) この引数の順番だから、 (map list function) -> (map list function) という風に処理をパイプライン化しやすい。
  • 72.
    関数呼び出しの優先順位 変数スコープにある関数 多重ディスパッチを登録しておけば、CLOS と同じように処理される。 第一引数のクラスに属する関数 多重ディスパッチで処理されなければ、 Java,Ruby のようにクラスのメソッドで処理される。
  • 73.
    非 CLOS なオブジェクトシステムJava ・ Ruby のようなクラス class Animal() def 鳴く () end end class 犬 (Animal) def 鳴く () (println “ わんわんお!” ) end def お手 () (println “ あいよ“ ) end end var dog = ( 犬 .new) ; var dog = (new 犬 )  どっちでもいいよ (dog. 鳴く ) ; ( 鳴く dog)  どっちでもいいよ [dog お手 ] ; Objective-C のメッセージ式と同じ
  • 74.
    非 CLOS なオブジェクトシステムclass 住所録 () var 名前 = “” var 住所 = “” var 電話番号 = “” def construct( 名前 住所 電話番号 ) set! self. 名前 = 名前 set! self. 住所 = 住所 set! self. 電話番号 = 電話番号 end def dump() (println 名前 “ : “ 住所 “ : “ 電話番号 ) end end var obj = (new 住所録 “ mitamex” “ 千葉県” “ 090-xxxx-xxxx”)
  • 75.
    SLOT じゃなければ、コピペで抜き出して簡単にテストできるよ var 名前 = “” var 住所 = “” var 電話番号 = “” def construct( 名前 住所 電話番号 ) set! self. 名前 = 名前 set! self. 住所 = 住所 set! self. 電話番号 = 電話番号 end def dump() (println 名前 “ : “ 住所 “ : “ 電話番号 ) end L4u>set! 名前 = “ 阿部高和” L4u>(dump)
  • 76.
    なぜ CLOS があるのにJava っぽいクラスを使うか ホスト言語が Java だから。 L4u の遅い部分はホスト言語で書きなおすので、同じ様な形が好ましい。 ホスト言語のオブジェクトを簡単に呼び出せるので、ホスト言語と同じ形のオブジェクトにしたかった。 var msgbox = (create &quot;System.windows.forms.MessageBox”) (msgbox.show &quot;Hello world&quot;)
  • 77.
    まとめ 楽するために L4uを使おう! どこでも REPL プロトタイプ作成ー>ボトルネックをホスト言語で最適化 超並列型 Algol 系プログラマでもとっつきやすい構文 携帯電話でも動く小さなコア 携帯電話からサーバーまでカバーするスケーラビリティ
  • 78.
    ありがとうございました 開発者募集中! 2009年オープンソースで登場予定