SlideShare une entreprise Scribd logo
1  sur  58
括弧への異常な愛情 または私は如何にして心配するのを止めて Common Lisp  を愛するようになったか Shibuya.lisp  テクニカル・トーク #7 アリエル・ネットワーク株式会社 松山朋洋
アジェンダ 1.  自己紹介 2. Lisp  に対する懐疑 3. Lisp  を始めた経緯 4. Lisp  との闘い 5.  なぜ  Lisp  なのか 6. Lisper's Delight
1.  自己紹介 松山 朋洋 アリエル・ネットワーク株式会社 @m 2ym  http://cx4a.org/ 好きなエディタ GNU Emacs 作ったもの auto-complete.el, popwin.el, popup.el, mongo.el, rsense, gccsense, xkeyremap, etc
1.  自己紹介 プログラミング言語遍歴 2002 年〜 C 2003 年 Visual Basic 6 2003 年〜 2008 年 C++ 2006 年〜 GNU Emacs 2007 年〜 2010 年 Java 2007 年〜 Emacs Lisp 2009 年〜 Ruby 2010 年〜 OCaml, Haskell, Common Lisp パラダイム 手続き型・オブジェクト指向型に触れた期間が長く、関数型 や  Lisp  に触れた期間は短い。
2. Lisp  に対する懐疑
2. Lisp  に対する懐疑 腑に落ちない啓蒙文書 Beating the Averages (Paul Graham), Revenge of the Nerds (Paul Graham), How to Become a Hacker (Eric Raymond), Let Over Lambda (Doug Hoyte), etc
2. Lisp  に対する懐疑 キラーアプリケーションの少なさ それほど”パワフル”な言語なのに、キラーアプリケーションが少ない
2. Lisp  に対する懐疑 コミュニティの小ささ それほど”魅力的”な言語なのに、そのコミュニティは小さい
2. Lisp  に対する懐疑 標準化の停滞 それほど”人気”な言語なのに、なぜ標準化作業が停滞 ( Common Lisp )したり、遅々として進まない( Scheme )のか
2. Lisp  に対する懐疑 Lisp  の専売特許 ガベージコレクションやラムダ式、マクロの大部分はもはや  Lisp  の専売特許ではない
2. Lisp  に対する懐疑 Emacs Lisp  のひどさ ” 括弧だらけの C” 。これがあの ” Lisp”  か?
3. Lisp  を始めた経緯
3. Lisp  を始めた経緯 会社で立ちあがった、あるプロジェクト 当初は  Ruby on Rails  か  Pylons  の二択で考えていた。 ところが、  Common Lisp  はどうかと同僚の深町さんに勧誘され、とんとん拍子で決まってしまった。 これが悪夢の始まりであった。
4. Lisp  との闘い
4. Lisp  との闘い パッケージ パッケージの名前空間はグローバル。パッケージはモノシリックに設計するのが一般的。パッケージには以下の問題がある。 a.  名前衝突 b.  ニックネーム c.  不本意な  intern d.  面倒な  export
4. Lisp  との闘い a.  名前衝突 安易に  use-package  すると名前の衝突に弱くなるどころか、不可解なバグに悩まされる可能性がある。とはいっても一々  import  するのも面倒。 (defpackage foobar (:use :cl :alexandria)) (defpackage foobar (:use :cl) (:import-from :alexandria ...))
4. Lisp  との闘い b.  ニックネーム パッケージにニックネーム(あるいは)を付ける合理的な権限を持つのは、パッケージ作成者のみ。  Haskell, OCaml, Python  のように、パッケージに一時的に別名を与える手段がない。 -- Haskell -  可能 import qualified Data.Map as M ;; Common Lisp -  不可能 (defpackage foobar (:use :cl) (:rename :alexandria :alex))
4. Lisp  との闘い b.  ニックネーム また、パッケージを一時的に  use-package  することもで きない。 (* OCaml –  可能  *) let open List in rev (map (fun x -> succ x) [1; 2; 3]) ;; Common Lisp –  不可能 (with-use-package :alexandria (plist-alist (remove-from-plist '(:a 1 :b 2) :a))
4. Lisp  との闘い c.  不本意な  intern defpackage  中に不本意な  intern  が発生す る。 ;; *package* = cl-user  と仮定 (defpackage foobar (:use *my-varaible* :my-function)) cl-user  パッケージに  foobar  と  *my-variable*  、  keyword  パッケージに  my-function  が  intern  される。気にしたら負け。 (defpackage #:foobar  ;  潔癖症 (:use #:*my-varaible* #:my-function))
4. Lisp  との闘い d.  面倒な  export export  するのが結構面倒臭い。 ;;  いちいち  :export  に追加 (defpackage foobar (:use :cl) (:export :foo :bar ...)) Clojure  の  defn/defn-  に相当するものを用意するとか、  Go  のようにシンボルが大文字で始まる場合にリーダーがそのシンボルを  export  するなど、手段は色々。
4. Lisp  との闘い d.  面倒な  export 一つの解決策として  cl-annot  を開発した。  @  に続く二つのフォームをリストで包んで返す簡単なリーダーマクロ。 CL-USER> '@1+ 2 (1+ 2) CL-USER> '@export (defun foo () ...) (progn (export 'foo) (defun foo () ...))
4. Lisp  との闘い CLOS スロットアクセサの名前をどうするかは実は難しい問題。パッケージシステムに関連する問題でもある。 of  派、  prefix  派、  keyword  派があり、それぞれ一長一短。
4. Lisp  との闘い CLOS ;; of  派 (defclass person () ((name :accessor name-of) (age  :accessor age-of))) (name-of bob) => “Bob” (age-of bob) => 42 アクセサが総称関数であることのメリットを生かせるが、名前衝突しやすい。
4. Lisp  との闘い CLOS ;; prefix  派 (defclass person () ((name :accessor person-name) (age  :accessor person-age))) (person-name bob) => “Bob” (person-age bob) => 42 名前衝突の危険性は少ないが、冗長。また、継承したクラスのインスタンスに使う場合に、少し違和感がある。
4. Lisp  との闘い CLOS ;; keyword  派 (defclass person () ((name :accessor :name) (age  :accessor :age))) (:name bob) => “Bob” (:age bob) => 42 keyword  パッケージをグローバル名前空間に見立てるテクニック。使い勝手としてはダックタイピングに近くなるが、慣習として定着しなければ、さまざまな危険性を伴う。
4. Lisp  との闘い multiple-value-bind ネストした  multiple-value-bind  をもっと簡単に書きたい。 (multiple-value-bind (a b) (values 1 2) (multiple-value-bind (c d) (values 3 4) (+ a b c d)))
4. Lisp  との闘い multiple-value-bind マクロを自作したが、後に   metabang-bind  がまさにそれだと知った。 (metabang-bind:bind ((values a b) (values 1 2)) (values c d) (values 3 4))) (+ a b c d)) しかし全く使ってない。
4. Lisp  との闘い パターンマッチング metabang-bind  や  cl-pattern  でも可能だが、より高速な  ML  風のパターンマッチングが欲しかったため、  cl-pattern (後に  cl-adt  に統合)を開発した。 (match '(“Bob” 42) ((list “Alice” 30) :alice-30) ((list “Alice” 40) :alice-40) ((list “Bob”  30) :bob-30) ((list “Bob”  42) :bob-42)) しかし全く使ってない。
4. Lisp  との闘い loop 痒いところに手が届かない  loop  。特に、返り値に対して任意の変換を行えないことに不満を感じ、  cl-loop-plus  を開発した。 (defun vectorize (seq &optional (element-type '*)) (coerce seq `(vector ,element-type))) (loop for i from 0 below 100 by 2 collect i transform #'vectorize) 全く使わなかったため、廃棄。パーサー部分は  cl-ast  にマージ。複雑な  loop  は  iterate  で。
4. Lisp  との闘い 無名関数 一々、ラムダ式を書くのが面倒。 (find-if (lambda (x) (= (length x) 2)) seq) Clojure  のような無名関数シンタックスが欲しい。そこで  cl-anonfun  を開発した。 (find-if #%(= (length %) 2) seq) 全く使ってない。
4. Lisp  との闘い 安易なマクロ (defview index () (markup (:html (:body (:h1 “Hello, World”)))) このコードの本当の意味を理解するには、 defview  マクロの正確な定義を知っていなければならない。この手のマクロを安易に書いてしまうことが多々ある。
4. Lisp  との闘い 安易なマクロ 図らずも  cl-annot  が良い解決策を与えた。 @view (defun index () ...) アノテーションは、物事に新しい側面(アスペクト)を追加する。その意味で、マクロとは本質的に別物。 ;;  参考: caveman @url GET “/” (defun index (params) ...)
4. Lisp  との闘い キャッシュ 特定の関数をキャッシュ( memoize )する仕組みがなかった。そこで  clache  を開発した。  load-time-value  と  cl-annot  のおかげで非常にシンプルな設計となった。 ;;  宝石 (defmacro with-cache (key &body body) (once-only (key) (with-gensyms (cache) `(let ((,cache (load-time-value (make-hash-table :test 'equal)))) (or (gethash ,key ,cache) (setf (gethash ,key ,cache) (locally ,@body)))))))
4. Lisp  との闘い キャッシュ (defun fact (x) (with-cache x (if (<= x 1) 1 (* x (fact (1- x)))))) @cache (x) (defun fact (x) (if (<= x 1) 1 (* x (fact (1- x)))))
4. Lisp  との闘い リストの型指定子 リストといっても、  proper list, improper list, association list, property list  があって、  proper list  にも  heterogeneous proper list  と  homogeneous proper list  がある。それらを全て単に  list  と呼ぶには無理がある。 (defun f (l) (declare (type list l)) ;; l  の詳しい型が読み手にもコンパイラにも伝わらない ...)
4. Lisp  との闘い リストの型指定子 そこで  trivial-types  を開発した。 (declare (type proper-list l)) (declare (type (proper-list fixnum) l)) (declare (type (asscoation-list string fixnum) l)) (declare (type (property-list fixnum) l)) 積極的に利用している。
4. Lisp  との闘い Web  フレームワーク UnCommon Web ドキュメント皆無、瀕死 Weblocks ドキュメント皆無、瀕死 SymbolicWeb ドキュメント皆無、死亡
4. Lisp  との闘い Web  フレームワーク どれもこれもイマイチ。結局、  Hunchentoot  ( HTTP  サーバー)を直接操作することになった。 その裏で、深町さんが  Clack&Caveman  プロジェクトを始動させる。 ;;  当時のコード (defview index () (markup (:html (:body (:h1 “Hello, World”)))) (defroutes map (GET “/” index))
4. Lisp  との闘い データベース 多数のライブラリが存在する。理想は  AllegroCache  のようなオブジェクトキャッシュデータベース。 オープンソースで現実的な選択肢は、 Elephant, CLSQL, Postmodern  の三つ。結局、 CLSQL  を選択。 その裏で、  Rucksack  のハックと、  CLSQL  を使った  ORM  の開発を始める。最終的には、どちらも頓挫。
4. Lisp  との闘い CLSQL  の問題点 1 リーダーマクロに強く依存。 (select [name] :from [employee] :where [> [salary] 1000]) ;;  上と同じ (select (sql-expression :attribute 'name) :from (sql-expression :attribute 'employee) :where (sql-operation '> (sql-expression :attribute 'salary) 1000))
4. Lisp  との闘い CLSQL  の問題点 1 SBCL+SLIME  の環境では、  CLSQL  のリーダーマクロを有効にする以下のコードが正しく動作しない。 (clsql:enable-sql-reader-syntax) そもそも、  Common Lisp  にはリーダーマクロをうまく管理する手段がなかった。そこで  cl-syntax  を開発した。 (use-syntax :clsql)  ; CLSQL  のリーダーマクロを有効にする (use-syntax :cl-interpol) ; CL-INTERPOL  の〃
4. Lisp  との闘い CLSQL  の問題点 2 SQL  生成、データベースアクセス、簡易的な  ORM  、キャッシュ機構など、多数のレイヤーがモノシリックに組み込まれている。そのくせ、カラムの追加といった  DDL  の基本的な操作が定義されていない。 そこで  clsql-ddl  を開発した。新たな  DDL  は  clsql  パッケージに挿入される。 (clsql:rename-table [foo] [bar])  ; FOO  を  BAR  に改名 (clsql:add-column [person] '([age] fixnum)) ; PERSON  に  AGE  を追加
4. Lisp  との闘い 要点 1 Common Lisp  には、よほどのコストを掛けない限り、どうしようもない問題がいくつも存在する(パッケージシステム、 CLOS 等)。言わば「言語とユーザーとの溝」。それらを改善するには、処理系の実装あるいは仕様の策定を待たなければならない。
4. Lisp  との闘い 要点 2 便利系マクロは使わなくなることが多い( cl-loop-plus, metabang-bind, cl-pattern, cl-anonfun )。 恒久的価値を持つその他のマクロとの違い。 ;;  参考:  Why I D on't Like EVAL-ALWAYS -- Nikodemus Siivola (defmacro eval-always (&body body) `(eval-when (:compile-toplevel :load-toplevel :execute) ,@body))
4. Lisp  との闘い 要点 3 抽象化が非常にうまくいくこともある( clache )。全ての歯車がぴったり一致し、その上に新たな基盤が作られる。
4. Lisp  との闘い 要点 4 マンパワーが分散しやすく、途切れやすい( Web フレームワーク、データベース)。開発者一人一人の好みが多様。皆、カウボーイプログラマー。  MIT/Stanford  スタイルの弊害?
5.  なぜ  Lisp  なのか
5.  なぜ  Lisp  なのか 標準化されているから? 部分的には  Yes. HyperSpec, CLtL2  は人類の宝。そこから得る価値は多大。ただ、要点 1 で示したように、古くなった標準は時に足枷となるし、標準だからと言って、必ずしも正しいとは限らない。
5.  なぜ  Lisp  なのか マクロがあるから? 部分的には  Yes.  要点 3 で示したように、抽象化が非常にうまくいくケースもある。ただ、要点 2 で示したように、マクロがあるからといって、プログラミングがうまくいくとは限らない。マクロは単なる手段であり、その先にあるもっと本質的なものに注目したほうがよい。
5.  なぜ  Lisp  なのか “ パワフル”だから? No.  そんな幻想はとっとと捨てるべき。例えば  Common Lisp  と  Haskell  をとってみて、どちらが”パワフル”か言えるだろうか?
5.  なぜ  Lisp  なのか ライブラリがたくさんあるから? No.  結論 4 で示したとおり。
5.  なぜ  Lisp  なのか “ Growing a Language” “ (プログラミング)言語は成長可能でなくてはならない”と主張する  Guy Steele  の論文および講演動画。 心の中で全ての問題が解決した気がした。
5.  なぜ  Lisp  なのか 本当の理由 Lisp  は真の意味で最も”言語”に近いプログラミング言語であるから。 プログラミング言語が成長可能であることに比べれば、括弧の数が多いとか、”パワフル”であるとか、ライブラリがしょぼいとか、その他諸々は些細な問題である。 実は皆、無意識に本当の理由を理解しているのではないか。
6. Lisper's Delight 私の経験 Common Lisp  をひとしきり書いたあとで、試しに  Emacs Lisp  を書いてみると、以前より捗るどころか、出来あがるソースコードが、なんとも美しい。 auto-complete.el  と  mongo.el  を比較。
6. Lisper's Delight 私の経験 汚ないソースコードを綺麗にリファクタリングできたときや、うまい抽象化によって、物事をより直感的に表現できたときの喜び、また、それらを達成できないときの苦痛。 Lisp  を書いているとき、人は自由になれる。他のプログラミング言語では、どこか囚われてしまう。
6. Lisper's Delight 手段と目的 手段と目的を、あえて取り違えてみよう。  Lisp  でプログラミングすることは目的であり、ソフトウェアを開発することは手段でしかない。
6. Lisper's Delight 気分は小説家 小説家になった気分でプログラミングしてみよう。  Lisp  は言語であり、あなたは  Lisp  で物事を考え、  Lisp  で表現することができる。 他人の作品をよんでインスピレーションを得たり、世間が驚く表現方法を発明したりして、互いを切磋琢磨し、より充実した  Lisp  の文化を築きましょう。
ありがとうございました

Contenu connexe

Tendances

コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!amusementcreators
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装したt-sin
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safeKumazaki Hiroki
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説murachue
 
Yocto bspを作ってみた
Yocto bspを作ってみたYocto bspを作ってみた
Yocto bspを作ってみたwata2ki
 
Ethernetの受信処理
Ethernetの受信処理Ethernetの受信処理
Ethernetの受信処理Takuya ASADA
 
TUI作業で便利なソフト2題
TUI作業で便利なソフト2題TUI作業で便利なソフト2題
TUI作業で便利なソフト2題shimadah
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Masahito Zembutsu
 
Dockerライフサイクルの基礎 地雷を踏み抜けろ!
Dockerライフサイクルの基礎 地雷を踏み抜けろ!Dockerライフサイクルの基礎 地雷を踏み抜けろ!
Dockerライフサイクルの基礎 地雷を踏み抜けろ!Masahito Zembutsu
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーToru Makabe
 
プログラミング言語のマスコットとか紹介
プログラミング言語のマスコットとか紹介プログラミング言語のマスコットとか紹介
プログラミング言語のマスコットとか紹介Takaaki Hirano
 
Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例gree_tech
 
仮想化環境におけるパケットフォワーディング
仮想化環境におけるパケットフォワーディング仮想化環境におけるパケットフォワーディング
仮想化環境におけるパケットフォワーディングTakuya ASADA
 
20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdf20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdfKazuaki Ishizaki
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Kohei Tokunaga
 
Drone.io のご紹介
Drone.io のご紹介Drone.io のご紹介
Drone.io のご紹介Uchio Kondo
 
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略祐司 伊藤
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All ThingsUnityTechnologiesJapan002
 

Tendances (20)

コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safe
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
Yocto bspを作ってみた
Yocto bspを作ってみたYocto bspを作ってみた
Yocto bspを作ってみた
 
Ethernetの受信処理
Ethernetの受信処理Ethernetの受信処理
Ethernetの受信処理
 
TUI作業で便利なソフト2題
TUI作業で便利なソフト2題TUI作業で便利なソフト2題
TUI作業で便利なソフト2題
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
 
Dockerライフサイクルの基礎 地雷を踏み抜けろ!
Dockerライフサイクルの基礎 地雷を踏み抜けろ!Dockerライフサイクルの基礎 地雷を踏み抜けろ!
Dockerライフサイクルの基礎 地雷を踏み抜けろ!
 
Docker Swarm入門
Docker Swarm入門Docker Swarm入門
Docker Swarm入門
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
 
プログラミング言語のマスコットとか紹介
プログラミング言語のマスコットとか紹介プログラミング言語のマスコットとか紹介
プログラミング言語のマスコットとか紹介
 
Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例
 
仮想化環境におけるパケットフォワーディング
仮想化環境におけるパケットフォワーディング仮想化環境におけるパケットフォワーディング
仮想化環境におけるパケットフォワーディング
 
20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdf20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdf
 
OpenStack Swift紹介
OpenStack Swift紹介OpenStack Swift紹介
OpenStack Swift紹介
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
Drone.io のご紹介
Drone.io のご紹介Drone.io のご紹介
Drone.io のご紹介
 
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
 

Similaire à 括弧への異常な愛情 または私は如何にして心配するのを止めてCommon Lispを愛するようになったか

Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Ransui Iso
 
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Ransui Iso
 
cl-waffe2 実装
cl-waffe2 実装cl-waffe2 実装
cl-waffe2 実装hiketteinya
 
OpenStack + Common Lisp
OpenStack + Common LispOpenStack + Common Lisp
OpenStack + Common Lispirix_jp
 
Proof and Emacs
Proof and EmacsProof and Emacs
Proof and Emacsdico_leque
 
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~infinite_loop
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Nextdynamis
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめLispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめSatoshi imai
 
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフト
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフトobjc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフト
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフトTaketo Sano
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Rubymitim
 
安全なプログラムの作り方
安全なプログラムの作り方安全なプログラムの作り方
安全なプログラムの作り方Kazuhiro Nishiyama
 
Lisp batton - Common LISP
Lisp batton - Common LISPLisp batton - Common LISP
Lisp batton - Common LISPMasaomi CHIBA
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
From Java To Clojure
From Java To ClojureFrom Java To Clojure
From Java To ClojureKent Ohashi
 
20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)Yoshifumi Yamaguchi
 

Similaire à 括弧への異常な愛情 または私は如何にして心配するのを止めてCommon Lispを愛するようになったか (20)

Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6
 
cl-waffe2 実装
cl-waffe2 実装cl-waffe2 実装
cl-waffe2 実装
 
OpenStack + Common Lisp
OpenStack + Common LispOpenStack + Common Lisp
OpenStack + Common Lisp
 
Proof and Emacs
Proof and EmacsProof and Emacs
Proof and Emacs
 
Scheme to x86コンパイラ
Scheme to x86コンパイラScheme to x86コンパイラ
Scheme to x86コンパイラ
 
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Next
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめLispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
 
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフト
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフトobjc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフト
objc2swift 〜 Objective-C から Swift への「コード&パラダイム」シフト
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Ruby
 
安全なプログラムの作り方
安全なプログラムの作り方安全なプログラムの作り方
安全なプログラムの作り方
 
Lisp batton - Common LISP
Lisp batton - Common LISPLisp batton - Common LISP
Lisp batton - Common LISP
 
Lisperはじめました
LisperはじめましたLisperはじめました
Lisperはじめました
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
From Java To Clojure
From Java To ClojureFrom Java To Clojure
From Java To Clojure
 
20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 

括弧への異常な愛情 または私は如何にして心配するのを止めてCommon Lispを愛するようになったか

  • 1. 括弧への異常な愛情 または私は如何にして心配するのを止めて Common Lisp を愛するようになったか Shibuya.lisp テクニカル・トーク #7 アリエル・ネットワーク株式会社 松山朋洋
  • 2. アジェンダ 1. 自己紹介 2. Lisp に対する懐疑 3. Lisp を始めた経緯 4. Lisp との闘い 5. なぜ Lisp なのか 6. Lisper's Delight
  • 3. 1. 自己紹介 松山 朋洋 アリエル・ネットワーク株式会社 @m 2ym http://cx4a.org/ 好きなエディタ GNU Emacs 作ったもの auto-complete.el, popwin.el, popup.el, mongo.el, rsense, gccsense, xkeyremap, etc
  • 4. 1. 自己紹介 プログラミング言語遍歴 2002 年〜 C 2003 年 Visual Basic 6 2003 年〜 2008 年 C++ 2006 年〜 GNU Emacs 2007 年〜 2010 年 Java 2007 年〜 Emacs Lisp 2009 年〜 Ruby 2010 年〜 OCaml, Haskell, Common Lisp パラダイム 手続き型・オブジェクト指向型に触れた期間が長く、関数型 や Lisp に触れた期間は短い。
  • 5. 2. Lisp に対する懐疑
  • 6. 2. Lisp に対する懐疑 腑に落ちない啓蒙文書 Beating the Averages (Paul Graham), Revenge of the Nerds (Paul Graham), How to Become a Hacker (Eric Raymond), Let Over Lambda (Doug Hoyte), etc
  • 7. 2. Lisp に対する懐疑 キラーアプリケーションの少なさ それほど”パワフル”な言語なのに、キラーアプリケーションが少ない
  • 8. 2. Lisp に対する懐疑 コミュニティの小ささ それほど”魅力的”な言語なのに、そのコミュニティは小さい
  • 9. 2. Lisp に対する懐疑 標準化の停滞 それほど”人気”な言語なのに、なぜ標準化作業が停滞 ( Common Lisp )したり、遅々として進まない( Scheme )のか
  • 10. 2. Lisp に対する懐疑 Lisp の専売特許 ガベージコレクションやラムダ式、マクロの大部分はもはや Lisp の専売特許ではない
  • 11. 2. Lisp に対する懐疑 Emacs Lisp のひどさ ” 括弧だらけの C” 。これがあの ” Lisp” か?
  • 12. 3. Lisp を始めた経緯
  • 13. 3. Lisp を始めた経緯 会社で立ちあがった、あるプロジェクト 当初は Ruby on Rails か Pylons の二択で考えていた。 ところが、 Common Lisp はどうかと同僚の深町さんに勧誘され、とんとん拍子で決まってしまった。 これが悪夢の始まりであった。
  • 14. 4. Lisp との闘い
  • 15. 4. Lisp との闘い パッケージ パッケージの名前空間はグローバル。パッケージはモノシリックに設計するのが一般的。パッケージには以下の問題がある。 a. 名前衝突 b. ニックネーム c. 不本意な intern d. 面倒な export
  • 16. 4. Lisp との闘い a. 名前衝突 安易に use-package すると名前の衝突に弱くなるどころか、不可解なバグに悩まされる可能性がある。とはいっても一々 import するのも面倒。 (defpackage foobar (:use :cl :alexandria)) (defpackage foobar (:use :cl) (:import-from :alexandria ...))
  • 17. 4. Lisp との闘い b. ニックネーム パッケージにニックネーム(あるいは)を付ける合理的な権限を持つのは、パッケージ作成者のみ。 Haskell, OCaml, Python のように、パッケージに一時的に別名を与える手段がない。 -- Haskell - 可能 import qualified Data.Map as M ;; Common Lisp - 不可能 (defpackage foobar (:use :cl) (:rename :alexandria :alex))
  • 18. 4. Lisp との闘い b. ニックネーム また、パッケージを一時的に use-package することもで きない。 (* OCaml – 可能 *) let open List in rev (map (fun x -> succ x) [1; 2; 3]) ;; Common Lisp – 不可能 (with-use-package :alexandria (plist-alist (remove-from-plist '(:a 1 :b 2) :a))
  • 19. 4. Lisp との闘い c. 不本意な intern defpackage 中に不本意な intern が発生す る。 ;; *package* = cl-user と仮定 (defpackage foobar (:use *my-varaible* :my-function)) cl-user パッケージに foobar と *my-variable* 、 keyword パッケージに my-function が intern される。気にしたら負け。 (defpackage #:foobar ; 潔癖症 (:use #:*my-varaible* #:my-function))
  • 20. 4. Lisp との闘い d. 面倒な export export するのが結構面倒臭い。 ;; いちいち :export に追加 (defpackage foobar (:use :cl) (:export :foo :bar ...)) Clojure の defn/defn- に相当するものを用意するとか、 Go のようにシンボルが大文字で始まる場合にリーダーがそのシンボルを export するなど、手段は色々。
  • 21. 4. Lisp との闘い d. 面倒な export 一つの解決策として cl-annot を開発した。 @ に続く二つのフォームをリストで包んで返す簡単なリーダーマクロ。 CL-USER> '@1+ 2 (1+ 2) CL-USER> '@export (defun foo () ...) (progn (export 'foo) (defun foo () ...))
  • 22. 4. Lisp との闘い CLOS スロットアクセサの名前をどうするかは実は難しい問題。パッケージシステムに関連する問題でもある。 of 派、 prefix 派、 keyword 派があり、それぞれ一長一短。
  • 23. 4. Lisp との闘い CLOS ;; of 派 (defclass person () ((name :accessor name-of) (age :accessor age-of))) (name-of bob) => “Bob” (age-of bob) => 42 アクセサが総称関数であることのメリットを生かせるが、名前衝突しやすい。
  • 24. 4. Lisp との闘い CLOS ;; prefix 派 (defclass person () ((name :accessor person-name) (age :accessor person-age))) (person-name bob) => “Bob” (person-age bob) => 42 名前衝突の危険性は少ないが、冗長。また、継承したクラスのインスタンスに使う場合に、少し違和感がある。
  • 25. 4. Lisp との闘い CLOS ;; keyword 派 (defclass person () ((name :accessor :name) (age :accessor :age))) (:name bob) => “Bob” (:age bob) => 42 keyword パッケージをグローバル名前空間に見立てるテクニック。使い勝手としてはダックタイピングに近くなるが、慣習として定着しなければ、さまざまな危険性を伴う。
  • 26. 4. Lisp との闘い multiple-value-bind ネストした multiple-value-bind をもっと簡単に書きたい。 (multiple-value-bind (a b) (values 1 2) (multiple-value-bind (c d) (values 3 4) (+ a b c d)))
  • 27. 4. Lisp との闘い multiple-value-bind マクロを自作したが、後に metabang-bind がまさにそれだと知った。 (metabang-bind:bind ((values a b) (values 1 2)) (values c d) (values 3 4))) (+ a b c d)) しかし全く使ってない。
  • 28. 4. Lisp との闘い パターンマッチング metabang-bind や cl-pattern でも可能だが、より高速な ML 風のパターンマッチングが欲しかったため、 cl-pattern (後に cl-adt に統合)を開発した。 (match '(“Bob” 42) ((list “Alice” 30) :alice-30) ((list “Alice” 40) :alice-40) ((list “Bob” 30) :bob-30) ((list “Bob” 42) :bob-42)) しかし全く使ってない。
  • 29. 4. Lisp との闘い loop 痒いところに手が届かない loop 。特に、返り値に対して任意の変換を行えないことに不満を感じ、 cl-loop-plus を開発した。 (defun vectorize (seq &optional (element-type '*)) (coerce seq `(vector ,element-type))) (loop for i from 0 below 100 by 2 collect i transform #'vectorize) 全く使わなかったため、廃棄。パーサー部分は cl-ast にマージ。複雑な loop は iterate で。
  • 30. 4. Lisp との闘い 無名関数 一々、ラムダ式を書くのが面倒。 (find-if (lambda (x) (= (length x) 2)) seq) Clojure のような無名関数シンタックスが欲しい。そこで cl-anonfun を開発した。 (find-if #%(= (length %) 2) seq) 全く使ってない。
  • 31. 4. Lisp との闘い 安易なマクロ (defview index () (markup (:html (:body (:h1 “Hello, World”)))) このコードの本当の意味を理解するには、 defview マクロの正確な定義を知っていなければならない。この手のマクロを安易に書いてしまうことが多々ある。
  • 32. 4. Lisp との闘い 安易なマクロ 図らずも cl-annot が良い解決策を与えた。 @view (defun index () ...) アノテーションは、物事に新しい側面(アスペクト)を追加する。その意味で、マクロとは本質的に別物。 ;; 参考: caveman @url GET “/” (defun index (params) ...)
  • 33. 4. Lisp との闘い キャッシュ 特定の関数をキャッシュ( memoize )する仕組みがなかった。そこで clache を開発した。 load-time-value と cl-annot のおかげで非常にシンプルな設計となった。 ;; 宝石 (defmacro with-cache (key &body body) (once-only (key) (with-gensyms (cache) `(let ((,cache (load-time-value (make-hash-table :test 'equal)))) (or (gethash ,key ,cache) (setf (gethash ,key ,cache) (locally ,@body)))))))
  • 34. 4. Lisp との闘い キャッシュ (defun fact (x) (with-cache x (if (<= x 1) 1 (* x (fact (1- x)))))) @cache (x) (defun fact (x) (if (<= x 1) 1 (* x (fact (1- x)))))
  • 35. 4. Lisp との闘い リストの型指定子 リストといっても、 proper list, improper list, association list, property list があって、 proper list にも heterogeneous proper list と homogeneous proper list がある。それらを全て単に list と呼ぶには無理がある。 (defun f (l) (declare (type list l)) ;; l の詳しい型が読み手にもコンパイラにも伝わらない ...)
  • 36. 4. Lisp との闘い リストの型指定子 そこで trivial-types を開発した。 (declare (type proper-list l)) (declare (type (proper-list fixnum) l)) (declare (type (asscoation-list string fixnum) l)) (declare (type (property-list fixnum) l)) 積極的に利用している。
  • 37. 4. Lisp との闘い Web フレームワーク UnCommon Web ドキュメント皆無、瀕死 Weblocks ドキュメント皆無、瀕死 SymbolicWeb ドキュメント皆無、死亡
  • 38. 4. Lisp との闘い Web フレームワーク どれもこれもイマイチ。結局、 Hunchentoot ( HTTP サーバー)を直接操作することになった。 その裏で、深町さんが Clack&Caveman プロジェクトを始動させる。 ;; 当時のコード (defview index () (markup (:html (:body (:h1 “Hello, World”)))) (defroutes map (GET “/” index))
  • 39. 4. Lisp との闘い データベース 多数のライブラリが存在する。理想は AllegroCache のようなオブジェクトキャッシュデータベース。 オープンソースで現実的な選択肢は、 Elephant, CLSQL, Postmodern の三つ。結局、 CLSQL を選択。 その裏で、 Rucksack のハックと、 CLSQL を使った ORM の開発を始める。最終的には、どちらも頓挫。
  • 40. 4. Lisp との闘い CLSQL の問題点 1 リーダーマクロに強く依存。 (select [name] :from [employee] :where [> [salary] 1000]) ;; 上と同じ (select (sql-expression :attribute 'name) :from (sql-expression :attribute 'employee) :where (sql-operation '> (sql-expression :attribute 'salary) 1000))
  • 41. 4. Lisp との闘い CLSQL の問題点 1 SBCL+SLIME の環境では、 CLSQL のリーダーマクロを有効にする以下のコードが正しく動作しない。 (clsql:enable-sql-reader-syntax) そもそも、 Common Lisp にはリーダーマクロをうまく管理する手段がなかった。そこで cl-syntax を開発した。 (use-syntax :clsql) ; CLSQL のリーダーマクロを有効にする (use-syntax :cl-interpol) ; CL-INTERPOL の〃
  • 42. 4. Lisp との闘い CLSQL の問題点 2 SQL 生成、データベースアクセス、簡易的な ORM 、キャッシュ機構など、多数のレイヤーがモノシリックに組み込まれている。そのくせ、カラムの追加といった DDL の基本的な操作が定義されていない。 そこで clsql-ddl を開発した。新たな DDL は clsql パッケージに挿入される。 (clsql:rename-table [foo] [bar]) ; FOO を BAR に改名 (clsql:add-column [person] '([age] fixnum)) ; PERSON に AGE を追加
  • 43. 4. Lisp との闘い 要点 1 Common Lisp には、よほどのコストを掛けない限り、どうしようもない問題がいくつも存在する(パッケージシステム、 CLOS 等)。言わば「言語とユーザーとの溝」。それらを改善するには、処理系の実装あるいは仕様の策定を待たなければならない。
  • 44. 4. Lisp との闘い 要点 2 便利系マクロは使わなくなることが多い( cl-loop-plus, metabang-bind, cl-pattern, cl-anonfun )。 恒久的価値を持つその他のマクロとの違い。 ;; 参考: Why I D on't Like EVAL-ALWAYS -- Nikodemus Siivola (defmacro eval-always (&body body) `(eval-when (:compile-toplevel :load-toplevel :execute) ,@body))
  • 45. 4. Lisp との闘い 要点 3 抽象化が非常にうまくいくこともある( clache )。全ての歯車がぴったり一致し、その上に新たな基盤が作られる。
  • 46. 4. Lisp との闘い 要点 4 マンパワーが分散しやすく、途切れやすい( Web フレームワーク、データベース)。開発者一人一人の好みが多様。皆、カウボーイプログラマー。 MIT/Stanford スタイルの弊害?
  • 47. 5. なぜ Lisp なのか
  • 48. 5. なぜ Lisp なのか 標準化されているから? 部分的には Yes. HyperSpec, CLtL2 は人類の宝。そこから得る価値は多大。ただ、要点 1 で示したように、古くなった標準は時に足枷となるし、標準だからと言って、必ずしも正しいとは限らない。
  • 49. 5. なぜ Lisp なのか マクロがあるから? 部分的には Yes. 要点 3 で示したように、抽象化が非常にうまくいくケースもある。ただ、要点 2 で示したように、マクロがあるからといって、プログラミングがうまくいくとは限らない。マクロは単なる手段であり、その先にあるもっと本質的なものに注目したほうがよい。
  • 50. 5. なぜ Lisp なのか “ パワフル”だから? No. そんな幻想はとっとと捨てるべき。例えば Common Lisp と Haskell をとってみて、どちらが”パワフル”か言えるだろうか?
  • 51. 5. なぜ Lisp なのか ライブラリがたくさんあるから? No. 結論 4 で示したとおり。
  • 52. 5. なぜ Lisp なのか “ Growing a Language” “ (プログラミング)言語は成長可能でなくてはならない”と主張する Guy Steele の論文および講演動画。 心の中で全ての問題が解決した気がした。
  • 53. 5. なぜ Lisp なのか 本当の理由 Lisp は真の意味で最も”言語”に近いプログラミング言語であるから。 プログラミング言語が成長可能であることに比べれば、括弧の数が多いとか、”パワフル”であるとか、ライブラリがしょぼいとか、その他諸々は些細な問題である。 実は皆、無意識に本当の理由を理解しているのではないか。
  • 54. 6. Lisper's Delight 私の経験 Common Lisp をひとしきり書いたあとで、試しに Emacs Lisp を書いてみると、以前より捗るどころか、出来あがるソースコードが、なんとも美しい。 auto-complete.el と mongo.el を比較。
  • 55. 6. Lisper's Delight 私の経験 汚ないソースコードを綺麗にリファクタリングできたときや、うまい抽象化によって、物事をより直感的に表現できたときの喜び、また、それらを達成できないときの苦痛。 Lisp を書いているとき、人は自由になれる。他のプログラミング言語では、どこか囚われてしまう。
  • 56. 6. Lisper's Delight 手段と目的 手段と目的を、あえて取り違えてみよう。 Lisp でプログラミングすることは目的であり、ソフトウェアを開発することは手段でしかない。
  • 57. 6. Lisper's Delight 気分は小説家 小説家になった気分でプログラミングしてみよう。 Lisp は言語であり、あなたは Lisp で物事を考え、 Lisp で表現することができる。 他人の作品をよんでインスピレーションを得たり、世間が驚く表現方法を発明したりして、互いを切磋琢磨し、より充実した Lisp の文化を築きましょう。