XMonad-oid on Emacs &
More functional Emacs Lisp
岡田 健 (keno)
自己紹介
岡田 健 (keno, Twitter: @keno_ss)
京都大学 数理解析研究所
Lisper, Schemer
最近はHaskellに興味がある (質問していいですか)
けど実際はEmacs Lispばっかり書いてる
Emac...
作ったもの
個人的テーマ
「(最小の性能の犠牲で)読みやすく書きやすくデバッグしやすいEmacs
Lispの環境を整備しよう」
ewm.el (EmacsWMonad; XMonod-oid on Emacs)
debug-print.el (...
今日の話
XMonad-oid on Emacs
ewm.el
More functional Emacs Lisp
ERFI の紹介
hairs.el の紹介
XMonad-oid on Emacs
そもそもこれがやりたくて
(作り直したくて)
色々整備してる
今日は時間ないので無理
興味ある人は個人的に
More functional Emacs Lisp
Lispって関数型なの?
Lisp
No (by “Let Over Lambda”).
Scheme
Maybe yes.
参照透明性は言語では保証されないけど書き方としては推奨されている
Common Lisp
知らない
CLerも不満らし...
Emacs Lispは関数型?
Definitely no.
dynamic binding (not lexical binding)
let 内で lambda 使うときは注意しないとデバッグできないバグが
Emacs LispはCL寄りな...
けど最近は (emacs 24.3)
lexical-binding や closure が使えるように! (>= 24)
cl.el が cl-lib.el になって(一応)使ってもいいことになった
けど cl.el でできたことが一部できな...
ライブラリ書いた
(書いてる)
ERFI
えるふぃ (ポケモンではない)
Schemeの標準的なライブラリSRFI(+Gaucheの拡張)のEmacs版(にで
きたらいいな)とか既存のイディオム(覚えられんし読めん)の改善とか
SRFI 1: リストライブラリ
SRFI 2 ...
named let
普通の変数束縛 + 名前付き函数の束縛
(defun fact-slow (n) ; 非末尾再帰
(if (zerop n)
1
(* n (fact-slow (- n 1)))))
(defun fact/tco (n) ; 末尾再帰
(fact-aux n 1))
(defun...
末尾再帰の最適化
「Emacs Lispに末尾再帰の最適化が欲しい」という話は少なくとも2004年
にGNUのメーリングリストに流れてる. (Oliver Scholz, “tail recursion hack in
Emacs Lisp?”...
Scholz版 と nlet.el
コンパイル時にマクロで再帰呼び出しを while ループに書き換える
だがバグがあり使い物にならない
引数の評価の順序に依存 (nlet.el)
制限も強い
末尾再帰の形でなかったり progn を混ぜるとバ...
erfi:let
インターフェースは SRFI 5 (named let)
R5RSから末尾文脈の概念
実装はScholz版を参考に
nlet.el もbugは取れたけど生成されるコードの
質が良くなかった
例
(defun fact (n)
(erfi:let iter ((n 5) (r 1))
(if (zerop n)
r
(iter (1- n) (* r n)))))
(defun fact (n)
(let ((--erfi-cont...
入れ子の例: リストの等価性
(defun erfi:list= (elt= &rest xss)
(if (let1 len (length (car xss))
(not (erfi:every1 (lambda (xs) (eq len ...
Haskellの話
Haskellって良い言語ですよね
((圏論好きなので)Haskellの方に行ってみたい)
((でも) (括弧 (ない (と)) 不安))
LispはどんどんHaskellとかの良い点を取り込むべき
Gaucheも $ をマクロとして取り込んだ...
レコード構文data Person = Person { firstName :: String
, lastName :: String
, age :: Int
, phoneNumber :: String
} deriving (Sho...
Emacs Lispにも
レコード構文を
XMonad-oid on Emacsに使いたい(使ってる)
evm-util.el (2013年)
hairs.el (2014年)
ewm-util.el
cl.el の構造体を再帰的に非破壊的にコピー
構造体の(型)情報を動的に取得している
cl.el は getter は作るけど setter は作らない
setf (汎変数の仕組み)を使わざるを得ない
なので函数として...
hairs.el
(Haskell influenced record syntax)
動的型付け言語のLispだけどこういう部分では静的にやった方が良い
型情報を与えてやれば静的にできる
マクロとしてDSLを実装
コンパイルで効率の良いコード...
(hairs-copy '((:hoge . hoge)
(:fuga . fuga)
(:foo . foo)
(:bar . (:john "Smith" :jane "Smith")))
(with :alist
:hoge 'hogeh...
(cl-defstruct hairs:person name age sex)
(cl-defstruct hairs:group name description member)
(hairs-register-type
'((:struc...
Any questions or comments?
Twitter: @keno_ss
GitHub: https://github.com/kenoss
まだコード上げてない(近日中に)
コメント, 要望, pull-req歓迎
ありがとうございました
Twitter: @keno_ss
GitHub: https://github.com/kenoss
まだコード上げてない(近日中に)
コメント, 要望, pull-req歓迎
Upcoming SlideShare
Loading in …5
×

XMonad-oid on Emacs & More functional Emacs Lisp | 関数型LT大会

1,423 views

Published on

関数型LT大会 @クックパッド, 東京 2014/05/11 の発表スライドです.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,423
On SlideShare
0
From Embeds
0
Number of Embeds
134
Actions
Shares
0
Downloads
3
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

XMonad-oid on Emacs & More functional Emacs Lisp | 関数型LT大会

  1. 1. XMonad-oid on Emacs & More functional Emacs Lisp 岡田 健 (keno)
  2. 2. 自己紹介 岡田 健 (keno, Twitter: @keno_ss) 京都大学 数理解析研究所 Lisper, Schemer 最近はHaskellに興味がある (質問していいですか) けど実際はEmacs Lispばっかり書いてる Emacs Lispって不便な言語ですよね
  3. 3. 作ったもの 個人的テーマ 「(最小の性能の犠牲で)読みやすく書きやすくデバッグしやすいEmacs Lispの環境を整備しよう」 ewm.el (EmacsWMonad; XMonod-oid on Emacs) debug-print.el (Gauche’s nice printf-debugging) ERFI (SRFI in Emacs Lisp) hairs.el (Haskell influenced record syntax) 次はR7RSのdefine-library的な仕組みが欲しい (名前空間がないので)
  4. 4. 今日の話 XMonad-oid on Emacs ewm.el More functional Emacs Lisp ERFI の紹介 hairs.el の紹介
  5. 5. XMonad-oid on Emacs
  6. 6. そもそもこれがやりたくて (作り直したくて) 色々整備してる
  7. 7. 今日は時間ないので無理 興味ある人は個人的に
  8. 8. More functional Emacs Lisp
  9. 9. Lispって関数型なの? Lisp No (by “Let Over Lambda”). Scheme Maybe yes. 参照透明性は言語では保証されないけど書き方としては推奨されている Common Lisp 知らない CLerも不満らしい? (深町英太郎「誰向けかわからないCommon Lispでの 関数型プログラミング入門とその未来」)
  10. 10. Emacs Lispは関数型? Definitely no. dynamic binding (not lexical binding) let 内で lambda 使うときは注意しないとデバッグできないバグが Emacs LispはCL寄りなLisp (でも「cl.el使うな」って言われる) 末尾呼び出しの最適化がない (CL処理系の多くでは使えるけど) ループは while かCL系の loop とか do-times とか 函数が破壊的版しかないことが多い append-map! (mapcon) はあるけど append-map がない
  11. 11. けど最近は (emacs 24.3) lexical-binding や closure が使えるように! (>= 24) cl.el が cl-lib.el になって(一応)使ってもいいことになった けど cl.el でできたことが一部できなかったり面倒だったり gv.el (generalized variables; 汎変数)の仕組み(高階函数) pcase.el (ML-style pattern-matching macro for Elisp) でもまだ足りない. 動き始めたばかり.
  12. 12. ライブラリ書いた (書いてる)
  13. 13. ERFI えるふぃ (ポケモンではない) Schemeの標準的なライブラリSRFI(+Gaucheの拡張)のEmacs版(にで きたらいいな)とか既存のイディオム(覚えられんし読めん)の改善とか SRFI 1: リストライブラリ SRFI 2 26 61 67: and-let* cut cute cond case ecase SRFI 5: 名前付きlet, 末尾再帰の最適化 「Elisp は CL じゃねぇ!」と言ってるしこういうのあってもいいかなと
  14. 14. named let 普通の変数束縛 + 名前付き函数の束縛
  15. 15. (defun fact-slow (n) ; 非末尾再帰 (if (zerop n) 1 (* n (fact-slow (- n 1))))) (defun fact/tco (n) ; 末尾再帰 (fact-aux n 1)) (defun fact-aux (n r) (if (zerop n) r (fact-aux (- n 1) (* r n)))) (defun fact (n) ; 名前付きlet (let iter (n r) (if (zerop n) r (iter (- n 1) (* r n))))
  16. 16. 末尾再帰の最適化 「Emacs Lispに末尾再帰の最適化が欲しい」という話は少なくとも2004年 にGNUのメーリングリストに流れてる. (Oliver Scholz, “tail recursion hack in Emacs Lisp?”) 2013年までは nlet.el というのもあった. (今は消えてる) 「末尾再帰最適化は理論上は実装可能(unwindしちゃまずいケースを除いて) です。が、末尾再帰最適化が行なわれることを想定したコードを古いEmacs で実行すると悲惨なことになるので、結局のところ永遠に実装されないと思 います。」(わからん, Emacs Lisp で末尾再帰, コメント欄) 個人的な意見: 古いEmacsのことを考えて読めないプログラムを書きたくな いし読みたくない.
  17. 17. Scholz版 と nlet.el コンパイル時にマクロで再帰呼び出しを while ループに書き換える だがバグがあり使い物にならない 引数の評価の順序に依存 (nlet.el) 制限も強い 末尾再帰の形でなかったり progn を混ぜるとバグる 本当に扱いたいのは末尾再帰の場合だが書いてるときは色々試したい funcall とか mapcar できない 実は変換後のループが函数呼び出ししていて効率が悪い
  18. 18. erfi:let インターフェースは SRFI 5 (named let) R5RSから末尾文脈の概念 実装はScholz版を参考に nlet.el もbugは取れたけど生成されるコードの 質が良くなかった
  19. 19. 例 (defun fact (n) (erfi:let iter ((n 5) (r 1)) (if (zerop n) r (iter (1- n) (* r n))))) (defun fact (n) (let ((--erfi-continue-- t) (--erfi-result-- nil) (G4201 n) (G4202 1) (n nil) (r nil)) (while --erfi-continue-- (setq n G4201) (setq r G4202) (catch '--erfi-repeat-- (setq --erfi-result-- (if (zerop n) r (progn (setq G4201 (1- n)) (setq G4202 (* r n)) (throw '--erfi-repeat-- nil)))) (setq --erfi-continue-- nil))) --erfi-result--) 展開 変数適用順序 に非依存
  20. 20. 入れ子の例: リストの等価性 (defun erfi:list= (elt= &rest xss) (if (let1 len (length (car xss)) (not (erfi:every1 (lambda (xs) (eq len (length xs))) (cdr xss)))) nil (erfi:let outer-iter ((xss xss)) (if (null (cdr xss)) t (erfi:let inner-iter ((xs (car xss)) (ys (cadr xss))) (if (null xs) (outer-iter (cdr xss)) (and (funcall elt= (car xs) (car ys)) (inner-iter (cdr xs) (cdr ys))))))))) 流石に展開したのは載せられないので 家に帰ってmacroexpandしてね 生でwhileループで書きたくないものの一つ
  21. 21. Haskellの話
  22. 22. Haskellって良い言語ですよね ((圏論好きなので)Haskellの方に行ってみたい) ((でも) (括弧 (ない (と)) 不安)) LispはどんどんHaskellとかの良い点を取り込むべき Gaucheも $ をマクロとして取り込んだりしてる 括弧があるからこそ簡単に可能なLispの強みのマクロ!! (とか言ったらHaskellerからマサカリ飛んできそう)
  23. 23. レコード構文data Person = Person { firstName :: String , lastName :: String , age :: Int , phoneNumber :: String } deriving (Show) data Book = Book { author :: Person , title :: String , price :: Int } derivin (Show) let author = Person "Saunders" "MacLane" 30 "unknown" let book = Book author "Categories for the Working Mathematician" 8500 book { author : author book { lastName : "Mac Lane" , age : 95 , phoneNumber : "unknown" } , price : 3000 }コピーして返す(非破壊的) 但しいくつかは新しい値に 再帰的に使える!
  24. 24. Emacs Lispにも レコード構文を XMonad-oid on Emacsに使いたい(使ってる) evm-util.el (2013年) hairs.el (2014年)
  25. 25. ewm-util.el cl.el の構造体を再帰的に非破壊的にコピー 構造体の(型)情報を動的に取得している cl.el は getter は作るけど setter は作らない setf (汎変数の仕組み)を使わざるを得ない なので函数として実装 (遅い)
  26. 26. hairs.el (Haskell influenced record syntax) 動的型付け言語のLispだけどこういう部分では静的にやった方が良い 型情報を与えてやれば静的にできる マクロとしてDSLを実装 コンパイルで効率の良いコードを生成 でもいちいち指定するのは面倒 型推論 (というほどのものではないけど) alist, plist, hash-table, array, struct, eieio (CLOS) に対応
  27. 27. (hairs-copy '((:hoge . hoge) (:fuga . fuga) (:foo . foo) (:bar . (:john "Smith" :jane "Smith"))) (with :alist :hoge 'hogehoge :foo => (lambda (x) (list x x)) :bar (with :plist :john "Hi" :jane "Hello"))) '((:hoge . hogehoge) (:fuga . fuga) (:foo . (foo foo)) (:bar . (:john "Hi" :jane "Hello"))) 固定値 型情報 古い値から 新しい値を作る 再帰的
  28. 28. (cl-defstruct hairs:person name age sex) (cl-defstruct hairs:group name description member) (hairs-register-type '((:struct hairs:group) member) '(:alist (:struct hairs:person))) (with (:struct hairs:group) :member (with :alist b (with (:struct hairs:person) :name "Neo"))) (with (:struct hairs:group) :member (w/ b (w/ :name "Neo")))
  29. 29. Any questions or comments? Twitter: @keno_ss GitHub: https://github.com/kenoss まだコード上げてない(近日中に) コメント, 要望, pull-req歓迎
  30. 30. ありがとうございました Twitter: @keno_ss GitHub: https://github.com/kenoss まだコード上げてない(近日中に) コメント, 要望, pull-req歓迎

×