2008-02-03
2008-01-30
■ Arc
g000001さんのところでArcという、Paul Graham氏が作ったという新しいLispが紹介されていた。
正直、Arcのことはなにもわからないけど、Paul Grahamってことに興味がある。
2008-01-27
■ Lispでいうところのコンパイルって、マシン語になるの?
Lispでいうところのコンパイルって、ネイティブのマシン語に落ちるんじゃなくてバイトコードになるだけだよね?Lispのコードがマシン語に落ちるところを想像できないんだけど…。xyzzyもそうだしコンパイラ - karetta.jp gaucheも仮想マシンで実行してるし。
と思ってたらGCLというGNUのCommonLispは、コンパイルするとCのソースを吐き出すらしい。マジで?単にバイトコードを実行するCソースが出るとかじゃなくて、例えば if がちゃんと分岐になったりするのかな?
- Optimization of GCL/KCL おぉ、完全にネイティブになってる、すごい。コンパイラどうなってんだ?
■ 小っちゃい処理系
俺にも理解できるような、小っちゃい処理系を探す。2ちゃんスレのテンプレから
CAMPUS LIsP
- 1000行。わかりやすい。
- マクロなし
TinyScheme
- コンパイルして動いた
- ソースファイルはほぼ1つだけど、4500行もあって、おっかない。
- TinySchemeは、MiniSchemeを元に作られてるとのこと
MiniScheme
- 1ファイルだけ。2400行。
- coded by Atsushi Moriwaki (11/5/1989)
- Revised by Akira KIDA
AMScheme
- Atsushi Moriwaki Lisp
- 内容的にはこっちのほうが古いのかな?
- R4RS
- ソースが小分けになっているので、場合によってはこっちのほうが理解しやすいかも。
KIScheme
- 日本語コメントなので安心
bit
■ バッククォート
同じくR5RSの「4.2.6 準引用」に、「(quasiquote (foo bar))」 で「`(foo bar)」、「(unquote a)」で「,a」、「(unquote-splicing a)」で「,@a」と同じと書いてある。
たけおか通りすがりの者です(もう、ここはチェックしないかも)
&& Optimization of GCL/KCL を書いている者です。
> コンパイラどうなってんだ?
CommonLispならコンパイルそのものは、あんまり難しくありませんよ。直感どおりにコードを生成すればよし。インタープリタからの呼び出しも、難しくはないはず。
問題は、実行中のLispインタープリタに、コンパイルした機械語コードをリンクする、いわゆる「インクリメンタル・リンク」を実現するテクニックです。それは、OSや、リンカを十分に理解していないと、うまく実装できないでしょう。
また、もっと本質的に難しいのは、ガーベジ・コレクタが動いたときに、コンパイルド・コードとうまく共存するかです。すごく単純に言うと、コンパイルド・コードが一時的に、リスト(など)のポインタを機械語レジスタの置いたときに、ガーベジ・コレクタが、そのレジスタをチェックしないと、矛盾が生じる、というような問題が出るので。
2008-01-26
■ qscheme を Windows で(失敗)
higepon氏の日記にQSchemeというリンクが張ってあった。見てみると
QScheme is a fast and small implementation of Scheme written in C. QScheme is easy to interface and should be easy to use as an extension language.
と書いてあるので、簡単に使えるのかと思ってダウンロードしてみた。
qschemeは
に依存しているとのこと。VC でのビルドは無理そうかな…。cygwinでコンパイルしてみる。
ffcall は、avcall, vacall, trampoline, callback の4つを含むライブラリで、qschemeでは avcall を使って任意の引数を持つCの関数を呼び出しているようだ。ffcallの ./configure は通るけどコンパイルがうまくいかない。avcall-i386.S からプリプロセッサで avcall-i386.s (小文字)に変換しているが、cygwin(windows) だとファイル名の大文字小文字の区別がないので、このせいでコンパイルできない。なので適当にファイル名を変える。vacall-i386.S も同様。
gmp は任意精度数演算ライブラリ。configure が cygwin に対応してなく、入れかたわからず。ググルと cygnwin のインストールで入れられるとのこと。cygwin を入れなおしたら qscheme の ./configure に成功。pcre はインストールしなくてもいいのか?
make をしてみる。vm2.c のコンパイル中に prim2.i(8) などでエラーが出る。Prim() マクロがおかしいようで、「l_##name##:」を「l_##name :」に変更。そうしても array.c で「scm_false が未定義」が出る。どこのヘッダにも定義してない。え~、どうなってるのよ~?
ううむ、ここまでか…。
2008-01-23
■ The Scheme Programming Language, 3rd Edition
The Scheme Programming Language, 3rd Edition もウェブで読めるとのこと。Scheme関連の本はウェブで公開されてる太っ腹な本が多くてうれしい限り。
これも読むリストに追加だ。目次の項目を見る限り、すごくオーソドックスな内容そうだな。
The Scheme Programming Language
- 作者: R. Kent Dybvig
- 出版社/メーカー: The MIT Press
- 発売日: 2003/09/26
- メディア: ペーパーバック
- クリック: 2回
- この商品を含むブログ (50件) を見る
JaylinI'm out of luaege here. Too much brain power on display!
dgmaosqoNYlqc <a href="http://kcaxzlanyzjp.com/">kcaxzlanyzjp</a>
qvntvsNqLovI , [url=http://aoionznbthxd.com/]aoionznbthxd[/url], [link=http://mbnmauoetljm.com/]mbnmauoetljm[/link], http://xyykizfudhew.com/
dxswvqVuF6FW , [url=http://rfylpvstheij.com/]rfylpvstheij[/url], [link=http://pmzpvynmxnfj.com/]pmzpvynmxnfj[/link], http://qpcuwyakevtf.com/
byuplmhoiwmIV , [url=http://pcfzxlxrvfau.com/]pcfzxlxrvfau[/url], [link=http://gvdtqybicqvh.com/]gvdtqybicqvh[/link], http://tbflskygwznp.com/
citmthc91XZGX , [url=http://eohimaxwgxay.com/]eohimaxwgxay[/url], [link=http://hruifwtmbhwo.com/]hruifwtmbhwo[/link], http://auytlcqnkpso.com/
hypkayeldlkkILHA0 , [url=http://iwvcnqzdkxhc.com/]iwvcnqzdkxhc[/url], [link=http://pllqhktnxupq.com/]pllqhktnxupq[/link], http://znungzulbyvp.com/
xqdwkjdxDfhzg , [url=http://ohkzgddegfwa.com/]ohkzgddegfwa[/url], [link=http://cfqstsoomzqr.com/]cfqstsoomzqr[/link], http://jcikjdlzzoch.com/
vikqssUJSSmH , [url=http://cfoyjwzpmbmt.com/]cfoyjwzpmbmt[/url], [link=http://ouvatnbxjsad.com/]ouvatnbxjsad[/link], http://yfwynmgolubl.com/
zvywxenna6uMhow , [url=http://wbrejkcmzxli.com/]wbrejkcmzxli[/url], [link=http://tkfxfjgborye.com/]tkfxfjgborye[/link], http://fzfgtbeialrg.com/
zfyagihkbt53t1i5 , [url=http://dytqptarlzrg.com/]dytqptarlzrg[/url], [link=http://zbmqjccnqccx.com/]zbmqjccnqccx[/link], http://bgopnnqhwhvx.com/
nawajauV1Sn2 , [url=http://onbcfsinrijx.com/]onbcfsinrijx[/url], [link=http://tybcoqjoaolu.com/]tybcoqjoaolu[/link], http://eqgxxhlekhtj.com/
kodphilckVYjzy , [url=http://agkjcicosrwg.com/]agkjcicosrwg[/url], [link=http://zpulydkeiudp.com/]zpulydkeiudp[/link], http://vriwziqsvigi.com/
boghtokvuqOsyG2 , [url=http://ymkatcjhortx.com/]ymkatcjhortx[/url], [link=http://hgtppwobtfwk.com/]hgtppwobtfwk[/link], http://qsacesvrtpxt.com/
lujeatgweFtpxF , [url=http://pywpkbdgbici.com/]pywpkbdgbici[/url], [link=http://vzxahixwaagr.com/]vzxahixwaagr[/link], http://lobbvljnnvib.com/
ooczwuwmKrwr5o <a href="http://ddrgpxzdghjs.com/">ddrgpxzdghjs</a>
2008-01-14
ChinaThere's a seecrt about your post. ICTYBTIHTKY
xxchqajxlAXOlk <a href="http://xmpzcthbqruz.com/">xmpzcthbqruz</a>
xxchqajxlAXOlk <a href="http://xmpzcthbqruz.com/">xmpzcthbqruz</a>
romdkglsgwfqbH0Iu , [url=http://mjpjuawhdpfo.com/]mjpjuawhdpfo[/url], [link=http://otsnxldypjjc.com/]otsnxldypjjc[/link], http://mzcqclcnmqcx.com/
pfddmwrgdpeHyQiOf , [url=http://rztnbqcmtype.com/]rztnbqcmtype[/url], [link=http://rzfwuphstoyk.com/]rzfwuphstoyk[/link], http://wxodptalwvmq.com/
2008-01-13
■ [PCL] Practical Common Lisp第12章 LISPと呼ばれる所以:リスト処理
- 12章でようやくリスト、ってどんな異端LISP本だよ!(いい意味で)
- 昔はリストだけで、vectorやハッシュテーブル、ユーザ定義構造体などはなかった
- 映画 Matrix のセリフに見立ててなんか書いてあるけど、意味がわからず…
- car, cdr はハナモゲラだから、first, rest を使おうか
関数プログラミングとリスト
- append は最後のリストはコピーしない
破壊的操作
■ [PCL] Practical Common Lisp第11章 コレクションの続き
http://gigamonkeys.com/book/collections.html
正月休み以来、ずいぶん開いちゃったな…。
ソートとマージ
- sort や stable-sort は破壊的なのか
- だけど、
(setf my-sequence (sort my-sequence #'string<))
と書かなきゃイカンとな。渡したシーケンスが破壊されるということであって、元のシーケンスがソートされるというわけではない、のかな?xyzzyでは大丈夫なようだけど。
部分シーケンス操作
- subseq で部分シーケンスが取れる、ので部分文字列の取り出しもこれでできる
シーケンス述語
- every, some, notany, notevery
- Common Lisp だと not.every とか not.some とか関数の合成が短く記述できないから、いちいち用意しないといけないのが辛いね
- 合成する関数を書くとこんな感じかね、funcall と apply が怪しいんだけども
(defun combine (fn1 fn2) (lambda (&rest rest) (funcall fn1 (apply fn2 rest))))
- not.every
(funcall (combine #'not #'every) #'evenp #(1 2 3 4 5)) ;=> t
- not.some = notany
(funcall (combine #'not #'some) #'evenp #(1 2 3 4 5)) ;=> nil '
- 合成はできるけど、funcall を書かないといけないのがメンドイから、
(defun my-notevery (pred &rest rest) (apply (combine #'not #'every) pred rest))
とかして定義を楽にするしかないんだろうなぁ。
シーケンス写像関数
ハッシュテーブル
- make-hash-table でハッシュを作れるけどキーの比較関数が eql なので、文字列をキーにする場合はうまくいかない、ので (make-hash-table :test 'equal) で作ればよい
- このサンプルや他のものでも、ハッシュのキーとしてシンボル「'foo」を使ってるけど、キーワードシンボルなら何度評価してもキーワードのままだからキーワードシンボル「:foo」を使うべきではないのかね?この辺の使い分けがよくわからんなぁ
- ハッシュにキーがないのか値がnilなのかを判定するために、gethash で多値を返して、それを multiple-value-bind で受け取ってあれこれするのってメンドウじゃないかなぁ?それより haskey? みたいなのが楽なのでは?
ハッシュテーブル走査
TailynnIf you want to get read, this is how you souhld write.
rxwmnyv8bJtzl <a href="http://ujtpzyamkqeg.com/">ujtpzyamkqeg</a>
jcspuzindJG7Mb , [url=http://fcvzbzkpwvst.com/]fcvzbzkpwvst[/url], [link=http://vcbsmdkifzrj.com/]vcbsmdkifzrj[/link], http://duxirpsiqreq.com/
vikirxrvVwkNvD , [url=http://ffcjjiyhanrv.com/]ffcjjiyhanrv[/url], [link=http://iwyigfxchope.com/]iwyigfxchope[/link], http://taevlexxnfcw.com/
2008-01-06
g000001こんにちは!
>|lisp|
(test 'a 1) ;=>nil
||<
の結果を見てアレ? エラーじゃないのかな?と思って、
Common Lispの処理系と、xyzzyで確認してみました。
普通のCommon Lispの処理系だと、エラーになるんですが、xyzzyだとnilになるんですね。
エディタとしての使い勝手を考えての仕様、とかでしょうか。
詳細は良く分からないのですが、とりあえず、ご報告まで。
mokeheheなるほど、本当ならちゃんとキーワードを与えないとエラーが出るものなんですね。
JacieVery valid, pithy, suciccnt, and on point. WD.
ctudlsupmdo1CdqVA <a href="http://yizbdweuhyfm.com/">yizbdweuhyfm</a>
upthixahOjO09 , [url=http://byucshnsvfro.com/]byucshnsvfro[/url], [link=http://jcfghstsxzow.com/]jcfghstsxzow[/link], http://xyjsoenwhabr.com/
pcgrvlfevhMcJ8f , [url=http://kqntvibyhwso.com/]kqntvibyhwso[/url], [link=http://dfgzdtrekepa.com/]dfgzdtrekepa[/link], http://gdamikcxrwsb.com/
2008-01-05
■ [PCL] Practical Common Lisp第11章 コレクション
http://gigamonkeys.com/book/collections.html
vector
- 固定サイズのvectorとリサイズ可能なvector
- 固定:vector 関数で作成できる
- より一般的な:make-array 固定も可変も作成可能、任意次元
- フィルポインタを持つ
- :adjustable で実際にリサイズ可能に
vectorのサブタイプ
- 文字列は要素がキャラクタに限定されたベクトルなので、次の章でベクトルを取る関数が文字列も受け取れることについて話す、とのこと。
- make-array で、:element-type に 'character を与えれば、文字列が作れる
(make-array 5 :fill-pointer 0 :adjustable t :element-type 'character) ;=> ""
- これにはビックリ!
- bit ベクトル
シーケンスとしてのvector
シーケンスをなめる関数
- いろんなキーワードで動作調整可能
- たくさんあって複雑という気がせんでもない
高階関数の種類
シーケンス全体の操作
■ [PCL] Practical Common Lisp第10章 数値、キャラクタ、文字列
略
■ [PCL] Practical Common Lisp第9章 実践:ユニットテストフレームワークの作成
- テスト結果は成功か失敗のどっちか
2つの最初の試み
- 全部のテストをandでつなぐ
- これだとどこで失敗したかわからない
- 個々に成功するか失敗するかを出力させる
- いちいち書くのがメンドイ、あと数が増えたら困る
リファクタリング
戻り値の修正
よりよいレポート結果
- いくつかテストケースを組み合わて、増えすぎた場合に今のレポートだと多すぎて探すのが大変
- グローバルにテスト名を保持する変数を作って、テストで設定し、結果表示する
抽象化あらわる
- テストケースの関数名と、テストケース名で2回設定してるのがムダ
- テスト関数だけど、それはあなたの心の中だけで、コードが特定のパターンにのっとっていること以外でテスト関数だとはわからない
- 中途半端な抽象化はソフトウェア構築の安っぽいツールにしかならない
- なぜなら中途半端な抽象化はパターンのマニフェストによってコードに表現されるので、大量のコードを複製する(メンテに問題が出る)ことで保障しなければならないからである
- より微妙には、抽象化はプログラマの心の中だけにあるので、別のプログラマ(または未来の自分)に同じ抽象化を理解させる方法がないことである
- 完璧な抽象化のためには、「これはテスト関数だ」ということを表現する方法と、パターンが必要とするすべてのコードが生成される必要がある
- すなわちマクロ
- deftest マクロを作る
テストの階層化
- *test-name* をリストにすればいい
まとめる
- 全部で26行!
■ Lispのリーダー
バッククォートとかカンマとかカンマアットとか、Lispのリーダーでどうやって処理してるんだろう?xyzzyでテスト:
(setf a 1234) (setf ls '(1 2 3))
としておいて、展開形は
`(hello ,a) ;=> (hello 1234) `(hello ,a world) ;=> (hello 1234 world) `(hello ,ls world) ;=> (hello (1 2 3) world) `(hello ,@ls world) ;=> (hello 1 2 3 world)
クォートをつけて、展開される前はどんなかをみると
'`(hello ,a) ;=> (list 'hello a) '`(hello ,a world) ;=> (list* 'hello a '(world)) '`(hello ,ls world) ;=> (list* 'hello ls '(world)) '`(hello ,@ls world) ;=> (cons 'hello (append ls '(world)))
うへぇ、場合分け多いな。
2008-01-04
■ [PCL] Practical Common Lisp第8章 マクロ:自分のを定義する
http://gigamonkeys.com/book/macros-defining-your-own.html
Macの話:単なる話
マクロがないLispを使ってた会社にMac氏が現れて、記述の置き換えの仕事をしていた、そしてそれはコンパイラに組み込まれましたとさ
マクロ展開時 vs 実行時
defmacro
マクロを書くステップ:
サンプルマクロ:do-primes
- 素数でループする、do-primes を書く
- loop を do で書くと
(defun primep (number) (when (> number 1) (do ((fac 2 (1+ fac))) ((> fac (isqrt number)) t) (if (zerop (mod number fac)) (return-from primep nil))))) (defun next-prime (number) (do ((n number (1+ n))) ((primep n) n) ))
- いいかげんloopからdoへの書き換えはメンドイな。loop マクロが書ければいいんだけど。
マクロパラメータ
- マクロへの引数はマクロコールを表現するソースコード
- デストラクティングバインドを使えば、リストからの取り出しをいちいち手で書かなくても大丈夫
- これを使えば、引数がおかしいときにも自動的にチェックできる
展開の生成
- バッククォートを使えば、カンマやカンマアットでクォートを打ち消すことができる
- カンマアットだとリストをその場に展開する
- 展開をチェックするには、実行結果を見るか
- macro-expand-1 を使って展開されたコードを見るか
漏れを塞ぐ
- Joel Spolskyの"The Law of Leaky Abstractions"の中で、抽象化をだいなしにしてしまう、詳細が漏れる抽象化のことを漏れやすい抽象化という用語を作り出した。
- マクロも抽象化の方法だから、漏れのないようにしないとね
- 現在の定義は漏れる可能性が3つある
- 1. 終了値が何度も評価されてしまう
- (random 100)
- "Principle of Least Astonishment " 驚き最小の法則
- 一度変数に入れておいて、それを使えばいい
- 1. 終了値が何度も評価されてしまう
(defmacro do-primes ((var start end) &body body) `(do ((ending-value ,end) (,var (next-prime ,start) (next-prime (1+ ,var)))) ((> ,var ending-value)) ,@body))
- 残念なことに、この修正がマクロ抽象化に新たに2つの漏れを発生させる
- 2. start と end の評価順が違う
(defmacro do-primes ((var start end) &body body) `(do ((,var (next-prime ,start) (next-prime (1+ ,var))) (ending-value ,end)) ((> ,var ending-value)) ,@body))
(defmacro do-primes ((var start end) &body body) (let ((ending-value-name (gensym))) `(do ((,var (next-prime ,start) (next-prime (1+ ,var))) (,ending-value-name ,end)) ((> ,var ,ending-value-name)) ,@body)))
マクロ作成時には以下のルールに従え:
リンク:
マクロを書くマクロ
(defmacro with-gensyms ((&rest names) &body body) `(let ,(loop for n in names collect `(,n (gensym))) ,@body))
他の古くからあるマクロを書くマクロ:once-only
(defmacro once-only ((&rest names) &body body) (let ((gensyms (loop for n in names collect (gensym)))) `(let (,@(loop for g in gensyms collect `(,g (gensym)))) `(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n))) ,(let (,@(loop for n in names for g in gensyms collect `(,n ,g))) ,@body)))))
- なにをやってるのかよくわからん
- 一番外側の (let ...) で、once-only に与えられたシンボル用にgensymをして、
- その内側の `(let ...) で1回だけ評価した値を格納するためのシンボルを作成、
- その内側で once-only に与えられたシンボルを評価してテンポラリに格納
- その内側で once-only に与えられたシンボルと同じ名前にバインドしなおす
- 一番最初の (let ((gensyms ... で、gensyms というシンボルを使ってしまっているため、もしonce-onlyの外側でgensymsを使ってたら動作がおかしくなると思うのだが…。
g000001はじめまして、自分もPCLを読んでみている者です。
自分はxyzzyはちょっと使ったことがある程度なのですが、
loopマクロはxyzzyにもlispディレクトリ以下に隠れてるらしいというのをどっかでみた記憶があったのを思い出して確認ちょっと確認してみました。
xyzzyだと(require "cmu_loop")で使えるようです。
cmuclから移植したのでこんな名前なのかもしれないですね。
mokeheheg000001さん、はじめまして。ブログ読ませてもらってます (^^;;
お書きのとおり、(require "cmu_loop") で本の中の loop が実行できました!ありがとうございます。
PCL を読むまで loop マクロというものを知りませんでした。
マクロだけでこんなムチャクチャできちゃうのはすごいですね。
loop は読みやすくていいですね。自分で書こうとは思いませんが (^^;;
Debrau9f3XY Touchdown! That's a really cool way of putting it!
lytiwaZECap3 <a href="http://srzjytyhymno.com/">srzjytyhymno</a>
yoshwamtUsHCYm , [url=http://fpvhnjgcsbyr.com/]fpvhnjgcsbyr[/url], [link=http://dujzatdeswnu.com/]dujzatdeswnu[/link], http://bgdvkybuwzjd.com/
rkmntuuwGmkbz , [url=http://pidabylfpbmq.com/]pidabylfpbmq[/url], [link=http://xekbosghhjxg.com/]xekbosghhjxg[/link], http://hyfwxibcjdmv.com/
ckazhuklcc4uc <a href="http://euvnhygtrqom.com/">euvnhygtrqom</a>
fvqnydtirkkgpYy , [url=http://zdkboicpubmh.com/]zdkboicpubmh[/url], [link=http://zeliqhxdzinl.com/]zeliqhxdzinl[/link], http://ahsqzzzpbfdq.com/
2008-01-03
■ [golf] Caesar cipher
TBS「新春超歴史ミステリー古代ローマ1000年史!!空前の巨大帝国全解明スペシャル」記念に、anarchy golf - Caesar cipherを解く:
; 1を足す (define (1+ x) (+ 1 x)) ; 文字を回転させる (define (rotate-char c start-char end-char n) (let ((cc (char->integer c)) (st (char->integer start-char)) (ed (char->integer end-char))) (if (and (<= st cc) (<= cc ed)) (integer->char (+ (modulo (+ (- cc st) n) (1+ (- ed st))) st)) c))) ; 文字列の文字ごとに関数を適用する (define (string-map fn str) (list->string (map fn (string->list str)))) ; 文字を暗号化 (define (caesar-cipher-char c n) (rotate-char (rotate-char c #\A #\Z n) #\a #\z n)) ; 文字列を暗号化 (define (caesar-cipher str n) (string-map (lambda (c) (caesar-cipher-char c n)) str)) (let ((str (read-line (current-input-port) #t))) (dotimes (i 26) (print (caesar-cipher str i))))
- エレガントさのかけらもない
- Schemeで数式を扱うと超わかりにくいな…
■ はてな記法に悩まされている
スーパーpre記法(シンタックス・ハイライト)が怪しい。バッククォート「`(」やスター「*)」などがあると中身が表示されなかったりする?スペースをつけると動作が変わる。謎。
■ [PCL] Practical Common Lisp第7章 マクロ
- 条件式やガベージコレクションなど、Lispをオリジナルにする多くのアイディアが他の言語に影響を与えた一方、引き続き Common Lisp を特別なものにしている特徴は、マクロのしくみだ。
- しかし、違う意味のマクロが広まってるおかげで、Common Lisp のマクロがいかにすばらしい特徴かを説明するのに苦労する
- プログラミング言語を、言語コア+標準ライブラリと定義すると、理解しやすく実装しやすくなる
- しかし、本当の利点は表現力にある
- 言語をライブラリだけと考えれば、その言語は簡単に拡張できるでしょ?
- マクロを使えば、新たな文法を作ることができる
when と unless
- if の then, else には式をひとつしか与えられないので、それ以上の式を与えたい場合 progn を使う必要がある
- if と progn を一緒にやってくれるのが欲しい
- それ when でできるよ
(defmacro mywhen (condition &rest body) `(if ,condition (progn ,@body)))
- 取るに足らないマクロの例だけど、利点はでかい
cond
- if ... else が複数つながると、インデントも深くなるし醜い
- cond でスッキリ
and, or, not
- and は偽が現れた時点で、orなら真が現れた時点で、残りの評価を打ち切る、のでマクロで定義される
ループ
- Lispの25の特殊オペレータは直接ループ構造をサポートしてはいない、マクロが構築している
- do: 汎用
- dolist, dotimes: リスト、回数ループに特化したもの
- loop: ミニ言語ぽい、Lispらしからぬ、英文ぽいループ用マクロ
- 賛否両論
dolist と dotimes
do
(do (variable-definition*) (end-test-form result-form*) statement*)
- do を使ってフィボナッチ数の計算
オールマイティなloop
- シンプルな使い方:無限ループ
(loop body-form*)
- 複雑な使い方:
- (loop for i from 1 to 10 collecting i) ==> (1 2 3 4 5 6 7 8 9 10)
- (loop for x from 1 to 10 summing (expt x 2)) ==> 385
- (loop for x across "the quick brown fox jumps over the lazy dog" counting (find x "aeiou")) ==> 11
- (loop for i below 10 and a = 0 then b and b = 1 then (+ b a) finally (return a))
- 22章で詳しく説明
- loopはwhenやifよりちょっと複雑なだけで同じマクロだから、もしloopが標準ライブラリになかったとしても自分で実装できるよ
"Practical Common Lisp"を読んでる方:
- Practical Common Lisp を読む ブログ名も。私も Scheme と Common Lisp の違いを知りたいですね、「#'つけなくていいとか?」レベルなんで。
■ [PCL] Practical Common Lisp第6章 変数
http://gigamonkeys.com/book/variables.html
変数の基礎
レキシカル変数とクロージャ
- デフォルトではCommon Lispでのすべてのバインディングフォームはレキシカルスコープを導入する。レキシカルスコープ変数はバインディングフォームの中のコードだけに参照される。
- Java, C, Perl, Python にもレキシカルスコープなローカル変数があるので、レキシカルスコープは馴染み深いはず。
- しかし、Common Lispのレキシカル変数はちょっとひねりがある
- レキシカルスコープ内部の無名関数からレキシカル変数を参照すると?
(let ((count 0)) #'(lambda () (setf count (1+ count))))
動的変数(特殊変数)
- defvar, または defparameter
- 慣習的に名前を *...* とする
- defparameter は常に値のセットを行う、defvar は変数が未定義の場合だけ
- 実際には、defvar を使うべき
- defvar や defparameter で定義した変数は特殊となり、動的変数になる。名前で見分けないと酷い目にあう。
よくわからん
定数
- defconstant
- 慣習的に名前は +...+
- すでに定義済みの定数を違う値でもう一度定義しても値は変わらない
代入
(defun foo (x) (setf x 10)) (let ((y 20)) (foo y) ; foo の結果はyには反映されず (print y)) ; => 20
setf とか setq の、f とか q ってなんなのさ?
一般化された代入
他の方法
CheyenneThanks alot - your answer solved all my problems after several days strugglnig
nbfblthxxwGRAJzH <a href="http://roatvosascrt.com/">roatvosascrt</a>
qzyiuizoR2ZyA1 <a href="http://rgsdbbodtlum.com/">rgsdbbodtlum</a>
pvnhwhdimayeS8qxq , [url=http://sivshzpfvyei.com/]sivshzpfvyei[/url], [link=http://lyzxzswvnxhi.com/]lyzxzswvnxhi[/link], http://abubbkybgqno.com/
2008-01-02
■ [PCL] Practical Common Lisp第5章 関数
新しい関数の定義
- defunマクロを使って定義する
関数パラメータリスト
オプションパラメータ
- 関数の引数リストに &optional をつける
- デフォルト値を nil 以外にしたい場合は (param-name vaue) にする
- 引数が与えられたかどうか知りたい場合は (param-name value supplied-p) とする
残りのパラメータ
キーワードパラメータ
- &key
- &optionalと&restのあと
- optionalと同様に、デフォルト値や引数が与えられたかを受け取ることができる
- キーワードと実際のパラメータ名を変えたい場合は、定義時にリストにすればできる
(defun foo (&key ((:apple a)) ((:box b) 0) ((:charlie c) 0 c-supplied-p)) (list a b c c-supplied-p))
上記のパラメータを混ぜて使うとき
- 必須パラメータ、オプションパラメータ、残りのパラメータ、キーワードパラメータの順に指定
- しかし、キーワードパラメータと混ぜると驚きの挙動になる
- &optionalと&keyを併用すると、オプションもキーワードもなしか、両方指定しか受け付けない
- &optionalはなくして、&keyだけにしたほうがいい
- &restと&keyは安全に組み合わせるが、最初は少し驚く
関数の戻り値
- 関数の最後の式の値
- return-from 特殊オペレータで
- return-from の最初の引数(ブロック名)はクォートの必要なし
- 関数名を指定して return-from だと、関数名を変えたときに一緒に変えなきゃいけなくてメンドイ、けどreturn-fromを陽に使う機械はそんなに多くないので実際はたいして問題にならない
データとしての関数(高階関数)
- defunは2つのことをしている:
- 特殊オペレータ function で関数オブジェクトが取得できる
- 「#'」も同じで、シンタックスシュガー
- 関数オブジェクトの呼び出しは:
- funcall
- apply
xyzzy-lispでは loop が単なる無限ループなので、plotはdoを使って
(defun plot (fn min max step) (do ((i min (+ i step))) ((> i max)) (dotimes (j (funcall fn i)) (format t "*")) (format t "~%")))
無名関数
■ [PCL] Practical Common Lisp第4章 シンタックスとセマンティクス (2)
関数呼び出し
特殊オペレータ
マクロ
- 2回評価される
- コンパイルした場合、マクロから関数やスペシャルフォームへの展開までが行われコンパイル済みコードとなり、実行時に展開済みコードが評価される
- マクロは関数と違って、コンパイラ内部へのフックを提供する
特殊オペレータとマクロって何が違うの?いっしょでよくない?
真、偽、そして等値性
- eq: オブジェクト同値。実装依存なので、数値やキャラクタの比較に使うべきではない。
- eql: 同じクラスのオブジェクトの2つの値が等しいか。同じクラスで値が等しい場合は真であることが保証される。別のクラスの場合等しくないことが保証される。
- この本では常にeqlを使う
- equal: リストや文字列の中身を見て比較してくれる。あとはeqlと一緒
- equalp: 大文字小文字を同一とみなす。整数と浮動小数も。リストの要素同士がequalpの場合、真。あとはeqlと一緒
Lispコードの整形
- 文法や意味的にではなく、コードの読み書きのためにインデント重要
- 閉じ括弧は別の行に書くな
2008-01-01
■ [PCL] Practical Common Lisp第4章 シンタックスとセマンティクス
てきとーに飛ばしつつ
なぜ括弧だらけなのか?
- 最初は、人間が書くときはM式(meta-expression) で書いてそれをS式に変換するつもりだったけど、結局S式のほうが好まれた
ブラックボックスを開ける
- 他の言語では、インタプリタやコンパイラ内部がブラックボックス
- 3段階:レクサー、パーサー、コード生成またはインタプリタ
- Lispでは2段階:リーダー(テキストからLispオブジェクトに変換)、エバリュエーター(それらのオブジェクトのセマンティクスを実装)
- コード生成が簡単にできる
- 存在するデータを使って。これはマクロの基礎
S式
Lispの形としてのS式
KristannaI much preefr informative articles like this to that high brow literature.
ytzwekgLPGf1g <a href="http://lobdermwcqes.com/">lobdermwcqes</a>
vtxhyppaZnV4I , [url=http://viiowtdcslur.com/]viiowtdcslur[/url], [link=http://yerzbudxpsda.com/]yerzbudxpsda[/link], http://gjzabrbwptmd.com/
dwycwoyszrlVRepr <a href="http://nvyxdtcfowsw.com/">nvyxdtcfowsw</a>
ysmtyen5wf79i , [url=http://digjcpoqoyen.com/]digjcpoqoyen[/url], [link=http://mphvpgjlyefd.com/]mphvpgjlyefd[/link], http://dahamnqaqmyu.com/
2007-12-31
■ 「プログラミングGauche」の本が出る
Gauche 作者の川合史朗さんが監修、内容はGaucheプログラミング(立読み版) - karetta.jpに大幅に加筆修正したもの、Kahua という継続ベースのアプリケーションフレームワークを使った内容、とか。超期待だぁ~!
■ [PCL] Practical Common Lisp第3章
実践:シンプルなデータベース
- 関数とマクロとスペシャルオペレータ:ここでは説明しないけど、ちょっとずつ違うと思ってくれ
- plist(プロパティリスト)
- シンボル:名前だと思ってくれ
- (list :a 1 :b 2 :c 3) でplist作成
- (getf (list :a 1 :b 2 :c 3) :a) でplistから取り出し
- プロンプトを出してCD情報の入力補佐関数
- *query-io* がよくわからず。(setf *query-io* t) 、(read-line) 、と変更
- y-or-n-p はミニバッファにプロンプトが出て、キーを押した後も消えない
- with-standard-io-syntax が定義されてない。無視。
データベースのクエリ
- (select :artist "Dixie Chicks") で探せるようにしよう
- remove-if-not : 二重否定で分かりづらいけど、Haskell でいうところの filter
- remove といっても、元のリストを変更するわけではなく、変更したものが戻り値として返る
- nonetheless : none-the-less にもかかわらず
(select (where :artist "Dixie Chicks")) (select (where :rating 10 :ripped nil))
と書けるようにするのは見事としかいいようがない。
レコードの更新
(コードの)重複を削除して、大きく勝利
- where 関数内で、要素ごとに下のように書いているのが美しくない!
(if title (equal (getf cd :title) title) t)
- (loop while fields ...) というのがエラー
- (loop ...) は xyzzy では無条件ループ
(while fields ...) に変更
- collecting とは?
- loop~collecting で、結果をリストとして返す?
- xyzzy lisp で make-comparisons-list はこんな感じかな?
(defun make-comparisons-list (fields) (let ((ls ())) (while fields (push (make-comparison-expr (pop fields) (pop fields)) ls)) (reverse ls)))
(macroexpand-1 '(where :title "Give Us a Break" :ripped t)) #'(lambda (cd) (and (equal (getf cd :title) "Give Us a Break") (equal (getf cd :ripped) t)))
ここまでほとんど一切細かい文法や仕組みを説明しないのもすごいな。ある程度分かってる人前提?
Wrapping Up
- コードの重複を取り除き、さらに効果的かつ一般化を同時に達成!
- 新しいwhereマクロは、plist形式のどんなデータベースでも使える
- 27章のMP3のデータベースで複数のテーブルや精巧なクエリを作るよ
補習
- update中のコードの重複を取り除いてみる
- (setf (getf row :title) title) のようなリストを作るマクロを作ればいい
- where のときに習って:
(defun make-setf-expr (field value) (list 'setf (list 'getf 'row field) value)) (defun make-setfs-list (fields) (let ((ls ())) (while fields (push (make-setf-expr (pop fields) (pop fields)) ls)) (reverse ls))) (defmacro update (selector-fn &rest clauses) `(setf *db* (mapcar #'(lambda (row) (when (funcall ,selector-fn row) ,@(make-setfs-list clauses)) row) *db*)))
- defmacro 内の、selector-fn にカンマをつけるのがわからなくてハマッた
- こうなると更に、where と update をまとめたくなるのう
りっぷる>xyzzy lisp で make-comparisons-list はこんな感じかな?
こんなのは、いかがでしょうかー。
(defun make-comparisons-list (fields)
(if fields
(cons (make-comparison-expr (first fields) (second fields))
(make-comparisons-list (rest (rest fields))))
nil))
Monkey7dGUYa Glad I've finally found something I agree with!
xcbnaacxoLg8nCe <a href="http://hrnaazbaxqwg.com/">hrnaazbaxqwg</a>
rzoydthrdloPKG8jn , [url=http://fgylqnwsduyc.com/]fgylqnwsduyc[/url], [link=http://rctcxoypqkmb.com/]rctcxoypqkmb[/link], http://qraumrvbzbnm.com/
gzskakd9MPsf <a href="http://vdagjlcacboo.com/">vdagjlcacboo</a>
アナフォリックマクロなどを使われてるようですね。