2011/04/04

lambda って



勉強になったのでメモしておく。


http://dev.ariel-networks.com/wp/archives/198


とくに、この部分



(lambda (x) x) ;; この"lambda" は lambdaマクロを持つフォーム
↓
#'(lambda (x) x) ;; この"lambda" は ラムダ式
↓
(function (lambda (x) x)) ;; この"lambda" は ラムダ式


と、この部分



(funcall '+ 1 2) ;; funcall が関数を取り出す
(funcall #'+ 1 2) ;; functionスペシャルフォームが関数を取り出す


はすごく分かりやすかった。





2011/04/03

xyzzy で trace を使ってみる



ウェブで lisp の入門とか講義テキストとかを見ていると、 trace という関数で呼び出しの引数と戻り値の履歴を確認できるようだ。


これは再帰を勉強しているときはめちゃめちゃ役に立つに違いない。


でも xyzzy には trace 関数がないみたいだ。じゃあ作ろうかと思っても、マクロ初心者のぼくには明らかに無理だ。


誰か作ってる人いないかなと探してみると・・・発見。ああ、あなたは神だ。




trace を使うには、



  1. encap をインストールする
    netinstaller でサクっと encap を入れる*1。

  2. trace.l をもらってくる
    さっきの神のページの使用例にあるので、これをコピってきて load-path の通ったところに置く。


の2段階が必要みたいだ。


入ったら早速テストしてみる。


練習でやった一番簡単な再帰、



(defun my-fact (n)
(if (= n 0) 1
(* n (my-fact (1- n)))))


コレ↑でやってみる。



(trace my-fact) ;; my-fact を trace の対象に

(my-fact 5) ;; 普通に C-j すると下記が "*Trace Output*"バッファに出力される
Calling (my-fact 5)
Calling (my-fact 4)
Calling (my-fact 3)
Calling (my-fact 2)
Calling (my-fact 1)
Calling (my-fact 0)
my-fact returned 1
my-fact returned 1
my-fact returned 2
my-fact returned 6
my-fact returned 24
my-fact returned 120
120

(untrace my-fact) ;; 使い終わったら trace の対象から外しておく

(trace) ;; 引数なしの (trace) は現在の trace 対象を返す


おお、いい感じだ。すばらしい。


ただ、今は練習中なので、いちいち *Trace Output*バッファに切り替えて確認するのがちょっとめんどくさいかな。


なので、C-j したらそのまま今のバッファに出力するように、trace-encap をちょこっとだけ変えさせてもらった。



;; mod
(defun trace-encap (func)
(unless (encapsulated-p func 'traced-function)
(encapsulate func 'traced-function
`(
;削除 ;(ed::setup-trace-output-buffer)
(setq *trace-depth* (1+ *trace-depth*))
;変更 ;(format *error-output* "~ACalling ~S~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) (cons ',func argument-list))
(format t "~ACalling ~S~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) (cons ',func argument-list))
(let ((#1=#:result (multiple-value-list (apply basic-definition argument-list))))
;変更 ;(format *error-output* "~A~S returned~{ ~A~}~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) ',func #1#)
(format t "~A~S returned~{ ~A~}~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) ',func #1#)
(setq *trace-depth* (1- *trace-depth*))
(values-list #1#))))
(push func *trace-function-list*)
func))


本当は「*scratch*バッファで呼んだとき以外は *Trace Output* バッファに出力する」ような関数を作ったほうがよさそうだけど、まあ今はこれでいいや。




trace のおかげで、再帰もずいぶん理解しやすくなった。それに、この encap.l を使えばいろいろ面白いことができそう。


がんばれば edebug も作れるかも。




*1:netinstaller --> kia's website の行で Enter --> encap の行で i を押す





netinstaller の操作



netinstaller のキーバインドを毎回忘れるので、デフォルトの状態の (describe-bindings) の結果を貼っておく。

(というか、xyzzy インストールフォルダの site-lisp/ni/readme.txt の50行目あたりをみればいいんだが。)

ついでにそれぞれのキーマップ名も書いておく。

----------------------------------------------
左ペイン (配布元一覧) ni::*site-map*
----------------------------------------------
key                 binding
---                 -------
C-k                 netinst::site-cut
RET                 netinst::site-apps-open
C-y                 netinst::site-paste
SPC                 netinst::site-apps-open
R                   netinst::site-update-all
a                   netinst::site-add
c                   netinst::category-show
d                   netinst::site-del
o                   netinst::site-open-in-browser
q                   netinst::finish
r                   netinst::site-update-current

Right               netinst::site-apps-open

----------------------------------------------
右ペイン (パッケージ一覧) ni::*apps-map*
----------------------------------------------
key                 binding
---                 -------
RET                 netinst::app-mark-toggle
SPC                 netinst::app-detail-open
A                   netinst::app-unmark-all
D                   netinst::app-uninstall-marked
I                   netinst::app-install-marked
U                   netinst::app-mark-updated
a                   netinst::app-mark-all
d                   netinst::app-uninstall-current
i                   netinst::app-install-current
n                   netinst::apps-show-next
p                   netinst::apps-show-prev
q                   netinst::apps-close
t                   netinst::apps-toggle


この netinstaller。最近になって使い出したけど、確かに便利だ。

でもコマンドを忘れるのが問題かな。debian の dselect を思い出す。




netinstaller のキーバインドを変えてみる



コマンドとキーマップがわかったので適当に変更してみる。

;; 配布元サイトをブラウザで開く
;; o --> e に変更
(define-key ni::*site-map* #\e 'ni::site-open-in-browser)
(undefine-key ni::*site-map* #\o)

;; アンインストール
;; d --> u に変更
(define-key ni::*apps-map* #\u 'ni::app-uninstall-current)
(undefine-key ni::*apps-map* #\d)


上記は .xyzzy の

(require "ni/setup")
(ni-autoload)


の後ろにでも書いておくといいと思う。




Android + Clojure > mini 9 + xyzzy ?



minimum で self な lisp 環境を Android でできないかと妄想してみる。


こんな条件ではどうかと。




  1. REPL が使える

  2. Emacs が走る

  3. lisp で書いた、その機械のアプリをセルフでビルドできる


1 は Clojure で、こんなのを見つけた。


2 これはすごいな。機種限定でさらにハックが前提みたいだけど、Emacs から電話したり SMS 飛ばしたりできてるみたい。


3 クロス環境な こんなのはよく見かけるけど、セルフ環境は発見できなかった。探し方が甘いかな。





非常に惜しい。使用感にもよるけど 3 さえ叶えばネットブックから乗り換えてもいいのにな。


でもま 1, 2 だけでも相当遊べそう。


とくに 2 はセルフなビルド環境とかなくても elisp だけでいいのかもしれないとか思わせてくれる。


じゃあ、ためしに softbank でキーボードつきのスマフォを物色してみよう・・・


GALAPAGOS 005SH


・・・キーボードつきって↑これだけ?まじ? 選択肢なし?


3D は全くいらんし、クロムメッキの縁取りは恥ずかしい。


ドコモなら LG のがあるけど、似たり寄ったり。


というわけで、まだスマフォは早いかなという結論にしとく。


ThinkPad 並みのマットな筐体のやつが出てきたらそのとき考えよう(結局外見か!)。


しかし、スマフォなんて、


「PI-3000時代のザウルスに毛が生えたようなもんだ。」


くらいにしか思ってなかったんだが、どうやらそうでもないらしい。