SlideShare ist ein Scribd-Unternehmen logo
1 von 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  の文化を築きましょう。
ありがとうございました

Weitere ähnliche Inhalte

Was ist angesagt?

Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Preferred Networks
 
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
CROOZ, inc.
 

Was ist angesagt? (20)

Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
Planet-scale Data Ingestion Pipeline: Bigdam
Planet-scale Data Ingestion Pipeline: BigdamPlanet-scale Data Ingestion Pipeline: Bigdam
Planet-scale Data Ingestion Pipeline: Bigdam
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
Rustに触れて私のPythonはどう変わったか
Rustに触れて私のPythonはどう変わったかRustに触れて私のPythonはどう変わったか
Rustに触れて私のPythonはどう変わったか
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
 
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
 
Tackling Complexity
Tackling ComplexityTackling Complexity
Tackling Complexity
 
SolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみようSolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみよう
 
MariaDB+GaleraClusterの運用事例(MySQL勉強会2016-01-28)
MariaDB+GaleraClusterの運用事例(MySQL勉強会2016-01-28)MariaDB+GaleraClusterの運用事例(MySQL勉強会2016-01-28)
MariaDB+GaleraClusterの運用事例(MySQL勉強会2016-01-28)
 
グラフデータベース入門
グラフデータベース入門グラフデータベース入門
グラフデータベース入門
 
Spark SQL - The internal -
Spark SQL - The internal -Spark SQL - The internal -
Spark SQL - The internal -
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
NVIDIA GPUで作るHeadless X11 Linux
NVIDIA GPUで作るHeadless X11 LinuxNVIDIA GPUで作るHeadless X11 Linux
NVIDIA GPUで作るHeadless X11 Linux
 
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
GitLab & web hooks & git-flowで実現する企業向けgit環境の構築
 
地理分散DBについて
地理分散DBについて地理分散DBについて
地理分散DBについて
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
Paxos
PaxosPaxos
Paxos
 
並行処理初心者のためのAkka入門
並行処理初心者のためのAkka入門並行処理初心者のためのAkka入門
並行処理初心者のためのAkka入門
 

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

Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
Ransui Iso
 
OpenStack + Common Lisp
OpenStack + Common LispOpenStack + Common Lisp
OpenStack + Common Lisp
irix_jp
 
Lisp batton - Common LISP
Lisp batton - Common LISPLisp batton - Common LISP
Lisp batton - Common LISP
Masaomi CHIBA
 

Ähnlich wie 括弧への異常な愛情 または私は如何にして心配するのを止めて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
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した
 
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事始め
 

Kürzlich hochgeladen

Kürzlich hochgeladen (7)

NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 

括弧への異常な愛情 または私は如何にして心配するのを止めて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 の文化を築きましょう。