2010/06/30

fib, tail-call-fib, lazy-fib

一般的な fib, 末尾再帰 fib, 遅延評価 fib ということで。(なんか途中に nlet が紛れ込んでますが)
遅延評価については、Gauche には util.stream というのがあるようです。馴染みがないです。


プログラミングClojureプログラミングGauche

2010/06/29

syntax-rules: ext-let

CL とか Clojure の destructuring-bind があればそれで済みそうですが、Gauche にはどうやらなさげ?

syntax-rules だとこんな感じでしょうか。。

これだと、(ext-let (a b)(1)(print a)) などでも動きます。(var ...) と (val ...) が同じ長さでない場合エラーにしたいって時はどうしたら良いのでしょうか。

追記

なんとなく希望に近い動きしてるように見えますが・・・。うーん・・・頭痛くなりますね。補助マクロとして切り出せば少しはマシに見えるのかもしれませんね。


追記2

こんな感じ?ヘルパー。


プログラミングGauche

Re: Clojure カッコイイ!

そういえば先日、@shunsuk さんから「Clojure を使うメリットって何?」と聞かれました。困りました。
  1. S式で Java が書ける
  2. Java の経験があって Lisp が好きな人はうれしい
この二つしか思い浮かびませんでした・・・。結局、両方とも同じ意味ですよね。。個人的にはこれくらいしかメリットが思い浮かびませんでした。Clojure の特徴はいろいろあると思うのですが、「Clojure でないと困る」とか「こういう時は Clojure が最適!」っていうケースがあるのか正直わかりませんし知りません。

私自身も、これから Clojure をメインで使いたいとか、プログラミングClojure を読み終えてからさらに勉強してみたいとも思えませんし・・・。

プログラミングClojure を読み終わったらもう一度考えてみたいと思います。っていうか、教えてエロい人!

追記

やっぱり、JVM で走って Java と仲の良い Lisp だからってことで FA?

プログラミングClojure

Clojure カッコイイ!

おもしろいページがあったのでメモ。

以下余談

遅ればせながら、プログラミングClojure を読んでいます。頂いてから随分経ってしまいました。。Clojure カッコイイですねぇ。おもしろいです。
今5章まで読んだところですが、5章(関数型プログラミング)とてもおもしろいです。
ここまでで良いなーと思った点は
  • 関数定義のコメント
  • doc 関数
  • 同名の関数で引数の数ごとに処理を記述できる(オーバーロードとか syntax-rules っぽいなーなどと)
  • 型ヒント
  • なんでもシーケンス
  • なんでも遅延シーケンス
  • Java の呼び出しが自然 (「S式で書ける Java」といった印象)
そういえば、多値とか継続はないっぽい?

やっぱり気になる。。といった点は
  1. 引数ベクタで[]しか使えない
  2. cond や let の括弧が少ない
両方とも好みの問題だと思います。1 は見る分には慣れてきました。書く時はやはり()で書けた方が好きです。2 は相変わらず見づらいです。でも両方とも大して気になりません。


プログラミングClojure

2010/06/24

syntax-rules: across (Clojure の .. ぽいもの)

プログラミングClojure P.62~ 「Clojure から Java を使う」より。
(.getLocation (.getCodeSource (.getProtectionDomain (.getClass '(1 2)))))

(.. '(1 2) getClass getProtectionDomain getCodeSource getLocation)
と書けますよーということのようです。

Java だと
'(1 2).getClass().getProtectionDomain().getCodeSourse().getLocation();
みたいなイメージで良いんでしょうかね。


scheme (gauche) の syntax-rules で書くと下記のような感じでしょうか。
良い名前が思いつきませんでした。当初は chain にしてましたが、なんとなく across に変えました。。

書いてみたコードは以下のようなもの。


追記

本家ソースはこれかな。

追記2

コメント欄で教えていただきました!名前が良いなぁ。
let1 要らないですね。。

プログラミングClojure

2010/06/20

なんで Lisp/Scheme の変数名は長いの?

そういえば。さっきの記事を書き終わって思い出しました。shiro さんがこんなことを仰っていた。
Lisp/Schemeの変数名が長くなりがちなのは、変数名にしか読者への情報を乗せられないということもあるな。静的型なら型名に情報を乗せて、変数名自体は一文字でもけっこういける。
だが型情報だけが乗せたい情報というわけでもない。とすれば一般的にメタ情報を乗せる仕組みをつくればいいか?
Clojureのmetaはそういう仕組みではあるな。
なるほどー。

ところで Clojure の meta ってなんだろ。プログラミングClojure P.54 の「メタデータ」のところのことかな。せっかく頂いたのにまだ読んでいない・・・。

追記

長いシンボルを補完できるエディタがあったからだと思います RT @valvallow: なんで Lisp/Scheme の変数名は長いの? http://ff.im/-moAHF

@wasabiz それもあるけど、組み込み関数の命名とかさ。Common Lispは「クソ長い」の。AT&TのC文化圏では「命名は短く」ってのがあって、それはテキストエディタで打つとメンドくせえし間違えるから。CLは関数名を「自動補完で記述する」前提があるんですよ。


追記


プログラミングGaucheプログラミングClojure

Common Lisp のなかで最も名前が長いシンボル

On Lisp の後注、P.400 にあるコードを試しに実行してみました。38文字て・・・。
以下の式は, 現在ののパッケージで可視になっているすべてのシンボルを名前の長い順に並べたリストを返す.
(以下のコードは本にあったコードに princ を追加したものです)


On Lisp

Lisp は「C 言語並みに速い」「C 言語より速い場合がある」

だそうです。

On Lisp

On Lisp 後注より
Gabriel, Richard P. Performance and Standardization. Proceedings of the First International Workshop on Lisp Evolution and Standardization, 1988, p.60
ある処理系で triangle を試していて, Gabriel は次のことを発見した:「プログラマが C コンパイラにレジスタ割り当ての指示を与えたときと比べても, C 版の反復による実装よりも Lisp 版のほうが 17% も高速だった.」彼の論文では Lisp で実装したほうが C より高速になるプログラムが他にもいくつか挙がっており, なかには 43% も高速になったものもある.

Lisp:よくある誤解

Lisp:よくある誤解 「Lispは高速なプログラムが書けない?」 より
LispでもほぼC並に速いコードを 書くことは可能です。
C並に速いLispコードは見た目も安全性もC並になる

ベンチマーク

こういうベンチマークもあるそうで

Let Over Lambda

Lisp の速度について、LET OVER LAMBDA Edition 1.0 では6章で扱っていました。
Lisp は速い。本当に速いのだ。
この章では、Lisp が他のあらゆるプログラミング言語よりも速くなり得ること、実は C のような低水準プログラミング言語は、マクロがかけているため、Lisp に対して性能面で不利なことを明らかするつもりである。 
参考までに LOL の6章の目次はこんな感じ。
  • 第6章
    • Lisp は速い
    • マクロが Lisp を速くする
    • ディスアセンブラと仲良くなる
    • ポインタスコープ
    • tlist とコンスプール
    • ソーティングネットワーク
    • コンパイラの書き方とベンチマーク 

参考


追記

まさか shiro さんのところに valvallow という文字が現れるようなことが起こるとは・・・。
すげーな Common Lisp ・・・。

追記2

How to make Lisp go faster than C
という論文が面白いです。
簡単な画像処理をCとCommon Lispで書いて速度を比べるというものですが、
CLの速度の劇的な変化が笑えます。
インタプリタで実行 -> Cの2300倍遅い
コンパイルして実行 -> Cの60倍遅い
型宣言と最適化を付ける -> Cと同等の速度(一部に関してはCより速い)

追記3

LET OVER LAMBDA Edition 1.0 P.75 より
(CL-PPCRE は、Common Lisp で書かれた正規表現ライブラリ)
第1に、CL-PPCRE は高速である。本当に高速だ。品質の良いネイティブコードコンパイラでコンパイルすれば、ほとんどの正規表現に対するベンチマークが、CL-PPCRE の方が Perl よりも2倍か、もっと高速だという結果をしばしば示す。そして、Perl の正規表現エンジンは、非 Lisp 正規表現エンジンの中では最高速なものの1つだ。それは C で書かれ、高度に最適化されたエンジンなのである。

LET OVER LAMBDA Edition 1.0


On Lisp 読了

ようやく LET OVER LAMBDA Edition 1.0 に引き続き On Lisp を読み終わりました。これが初級者向けってホントですか。前半はまー、確かにそうでしょうけども。。Lisp 怖い。


個人的におもしろかったのは、
  • Paul Graham 節
  • 前半の入門的なところ
  • ユーティリティ関数のところ
    • コードがキレイ
    • こういう風にユーティリティを書いていけば良いのかー。
  • マクロの導入的なところ
    • 「マクロとはこういうものだ」というのが随所に書かれていて、丁寧でわかりやすい
    • できること、できないこと、長所、短所、デバッグ方法、ハマりどころ
    • やっぱりマクロは難しいんだ
    • 「こうやって書いていけば良いよ」
  • アナフォリックマクロ
    • カッコイイ
  • 非決定性
    • とてもわかりやすい
  • CLOS
    • 言うほど異色じゃなくね?(ほんの少ししか紹介されていなかったからかも)
  • 付録のパッケージのところ
    • パッケージややこしそう。
でしょうか。

継続の実装のところは少し期待を裏切られました。あとATN コンパイラと Prolog のところは完全に置いていかれました。

コードがキレイですごく見やすかったです。お手本にしたいコード(当たり前か)。私は先に LET OVER LAMBDA Edition 1.0 を読みました。LOL もすごくおもしろかったのですが内容的にもコード的にも読むのに負荷が高かったです。On Lisp を先に読んだ方が良いのではないかと思います。


On LispLET OVER LAMBDA Edition 1.0

「最終的には Prolog を 94 行で実装した.」

Web 版にはないと思われますが、P.393以降の「後注」に以下の様なことが書かれています。
最終的には Prolog を 94 行で実装した. それには以前の章から 90 行分のユーティリティを持ってきて使っている. ATN コンパイラにはさらに 33 行を追加したので, 217 行になる. ただし Lisp の言語仕様上では行という概念が無いので, Lisp プログラムの長さを行数で図ると誤差が大きいことに注意.
最後の一文。
ただし Lisp の言語仕様上では行という概念が無いので, Lisp プログラムの長さを行数で図ると誤差が大きいことに注意.
そうですよね。。ならどんな単位で測ると良いんでしょうね。

そういえば、「Lisp は S/N 比が高いので・・・」どうのこうの、というようなことを良く見聞きしますが、S/N 比ってなんなんでしょう?
ノイズが少ないってことなんですかね。


On Lisp の後注がおもしろいですね。Yコンビネータが出てきたり、SICP(計算機プログラムの構造と解釈)が出てきたりします。Paul Graham は自分のやってる VC の名前を「Y Combinator」にしたり、SICP の原書にレビューしてたりと、きっと両方共好きなんでしょうね。SICP 原書のレビューの方には、最近話題(と、言っても原書は20年前のものらしい)の実用 Common Lisp (IT Architects’Archive CLASSIC MODER) の著者 Peter Norvig 氏もレビューしてますね。

On Lisp

「ファーストクラスの脱出手続き」

schemeは, ファースト・クラスの脱出手続きを採用した初めての広く使われたプログラミング言語であった
ってのは、やっぱ継続のことですよね。

継続は非局所的脱出, バックトラッキング, コルーチンなど広範囲の高度な制御構造を実装することに有用である。
とも。


プログラミングGauche

RnRS 年表と資料へのポインタ

ようやく R5RS を読み始めました。まだ始めの方しか読んでませんが、意外におもしろいです。
これなら R4RS や R3RS なんかもさかのぼって読んでみたい!と思いましたが、日本語訳は見当たりませんね。。やっぱり読むなら英語ですか・・・。


年号は R5RS 犬飼さん版日本語訳の P.2 「はじめに - 背景」を参考にしています。
1975年は、TCP/IP が公開されたり、Microsoft がスタートしたりした年みたいですね。


お、Practical Scheme にこんなページが。

追記

コメントにて R4RS は日本語訳があると教えて頂いたので、再度探してみました。
ここにリンクがあったのですが、リンク先は消失しているようです。

で、こちらに復刻版が!

プログラミングGaucheプログラミング言語SCHEME


2010/06/16

On Lisp 非決定性

On Lisp の非決定性の章がとてもわかりやすいです。以前写経した、syntax-rules 版の amb より、関数版の方がよくわかりました。
以下のコードは関数版の方です。取りあえず動かしてみました。


で、少し書き換えてみました。(Gauche)


その後、自分でも思いついたサンプルを書こうとしたのですが、思ったように動きません。。わかったようでわかっていないようです・・・。

On Lisp

2010/06/09

(syntax-rules () ((_ "hoge" args ...



プログラミングGauche

define-syntax: upto, downto

正確には知りませんが、 ruby にこんなのありますよね。



初めてのRuby

if-let1 の所在

On Lisp のアナフォリックマクロで aif というものがあります。scheme で書いてみたりしました。
Gauche には if-let1 があるということを教えて頂きました。
これですね。
で、grep してみたら lib/gauche/common-macros.scm の中にありました。このファイルはおもしろそうですね。。
;like aif in On Lisp, but explicit var
if-let1 なるほど、この名前しっくり。


ググってみると。



On Lisp

2010/06/08

Emacs windows.el 次のウィンドウ、前のウィンドウ

今まで C-. と C-, は、bs-cycle-next, bs-cycle-previous に割り当てていました。
これを C-> と C-< に変更して、C-. C-, は、windows.el の win-next-window, win-prev-window に割り当てました。
;; (global-set-key [?\C-,] 'bs-cycle-next)
;; (global-set-key [?\C-.] 'bs-cycle-previous)
(global-set-key [?\C-<] 'bs-cycle-next)
(global-set-key [?\C->] 'bs-cycle-previous)
(global-set-key "\C-x\C-b" 'bs-show)
(require 'windows)
(setq win:use-frame nil)
(win:startup-with-window)
(define-key ctl-x-map "C" 'see-you-again)
(global-set-key [?\C-.] 'win-next-window)
(global-set-key [?\C-,] 'win-prev-window)

.emacs 汚い・・・。整理したい。けど放置。

入門 GNU Emacs 第3版

2010/06/06

anaphora

else は、Common Lisp だと &optional else で良さそうだけど、syntax-rules だとどう書くのが良いのか。。
こういうのは、衛生的なマクロでなくて素直に伝統的なマクロで書いた方が良さそうですね。というか、伝統的なマクロでないと書けないですね。

acond は scheme だと必要なさそうですね。


On LispLET OVER LAMBDA Edition 1.0

condの節

これ知りませんでした。なんか、なんか、こうなってくれたらうれしそうな場面があったような・・・。。
gosh> (cond (#t))

#t


この形式って、何か名称ってあるんでしょうか。
(cond (#t => (cut display <>)))


プログラミングGauche

Gauche 文字列補間

ずっと補完だと思ってました。補間なんですね。
gosh> (define (hello name) #`"Hello, ,|name|!!")
hello
gosh> (hello 'valvallow)
"Hello, valvallow!!"

プログラミングGauche

Lisp/Scheme 読み物、メモ、よくわからないけど後で読む

Lisp関連の翻訳もの多数

社長がSchemerらしい。採用情報のページがなんかすごい。

Schemeのマクロ、継続関連。

コンパイラとか3impとか。

雑記

また探しに行ってみたけど、熊本の本屋さんには 実用 Common Lisp (IT Architects’Archive CLASSIC MODER) は置いてねぇーわ・・・。
ちょっと立ち読みしてみたいんだけどなぁ・・・。

実用 Common Lisp (IT Architects’Archive CLASSIC MODER)

2010/06/04

syntax-rules: define-memoize

以前、On Lisp に出てくるメモ化関数を試しに書いてみました。
追記で書きなおした方のものでも、再帰先の分まではメモってくれない、ということで良いと思います。そこで、マクロならなんとかなるかも知れない、と思って実験的に書いてみました。

こういうのはありなのか、これでちゃんと動くのか、よくわかりません。。
(let ((val (begin body ...))) ・・・) とか、これどうなんでしょう。



で、上記の単一引数のものが、なんとなく動いてるようなので、可変長引数に対応させてみようとしたところ行き詰まりました。


デバッグしてみるわけです。

そうか、#0# が (5) になって、5を関数として実行しようとしている、ということで良さそうです。
これがわかったから解決できたかというと、できていません。うーん。

追記


いつものごとく、@cametan_001 さんにアドバイス頂いて、... で書いてみたら取りあえず動くようになりましたー!

ところで、2引数以上でメモ化すると劇的に早くなる例が思いつきません・・・。眠いので、また明日 or 今度、ということで。

プログラミングGauche

2010/06/02

Re: syntax-rules: bind-variables

「...」だと、こうは書けないですよね。。
に反応頂きました!

写経したも同然ですが、早速自分なりに書いてみました。



オリジナルのコードだとsyntax-errorっての使ってますが、これはR5RSで定義されていないので、errorに差し替えています。
もっとも、2番目のパターンだとそれじゃあ怒られたので、syntax-errorの挙動がしりたいトコなんですけどねえ。
今読んでいるところまでには、出てきてないですね。
Gauche では、組み込みであるようです。
実行時ではなくマクロ展開時(すなわち、コンパイル時)に エラーを通知する

追記

あれ、これって「自分で書け」ってお題が出てるんですかね。
*** Write a syntax-error macro.
    Write `rejection' patterns by expanding into a call to
    syntax-error.

プログラミングGauche

syntax-rules: bind-variables

こういうの。
(bind-variables ((a 1)
            (b)
            c
            e
            (d (+ a 3)))
           (list a b c d e))
;; -> (1 #f #f 4 #f)

で、自分なりに書いてはみたものの・・・。かなり苦戦しました。
しかも複雑になってしまって、何が何やら。動いてはいるっぽいものの、これじゃーちょっと・・・。それに何よりダサい。


お手本はこちら。うーん、だいぶスッキリしていますね。「...」だと、こうは書けないですよね。。場合によってはドット対表現で書いた方がスッキリするんですね。


追記

書けてるー(笑)なるほどー。


プログラミングGauche

dotted Re: Re: syntax-rules: when, unless

ドット対でも書けるんですね。。(begin . body) って、最初見たとき「???」でしたよ。


プログラミングGauche

戻り値 Re: syntax-rules: when, unless

when や unless って、戻り値が undef より #f の方が好みかも。なぜその方が良いかと言われると困るけど・・・。未定義が返るより、安心するというか。



Gauche の when, unless って、戻り値が未定義なわけですが、もしかしてその方が良い理由とかあったりするのかなー。
まー、戻り値が欲しいケースに出会った時に、when を上書いてしまえば良いのかな。そういう問題でもないのかな。うーん。

上書くというかシャドウするとか。


when, unless で戻り値を利用するケースが発生すること自体、何か見直しが必要ということなのかも?

なんだか、以前も同じようなことをどこかで言ったような見たような・・・。そして教えてもらったような気も・・・。忘れた・・・orz

プログラミングGauche

Scheme マクロのデバッグ4種

マクロのデバッグ方法をいくつか。(* 追記あり)

expander

expander を使うのがオーソドックスみたいですね。
Gauche なら Common Lisp と同じく、macroexpand, macroexpand-1 などがあります。


mac

On Lisp よろしく mac マクロを定義しておくと便利そうです。


リーダーマクロ

Gacuhe #?= リーダーマクロはどうでしょう?うーん。


quote

これは初見。任意のパターンの展開部分を quote しちゃう。これは意外と便利かも知れません。
*** Debugging trick
One very easy debugging trick is to wrap the template with a quote:


複数のパターンがある場合に、特定のパターンだけ quote してみるとか・・・。


マクロ初心者な私の知る限りこんなところでしょうか・・・。

追記

gaucheにはmac相当の%macroexpandがあるみたいです。さらにsyntax-rulesマクロなどをmacroexpandした際の表示を見やすくするunwrap-syntaxも便利です。


追記



The Reasoned Schemer

Emacs 行末のスペースに色をつける

意図しない時に、行末にスペースが入ることがあって、イラっとしてました。
これで解決。

(when (boundp 'show-trailing-whitespace)
  (setq-default show-trailing-whitespace t))

色は初期状態では真っ赤なので、変更したければ以下のように指定。
(set-face-background 'trailing-whitespace "purple4")

入門 GNU Emacs 第3版

Emacs 任意のサイズと起動時のサイズを切り替える

こういうのわざわざ書く必要も無いんでしょうけども。
起動時のサイズと場所、任意のサイズと場所に変更できるだけでよかったので、書いてみました。

はじめに、こう書いてみたのですが、意図した通りに動いてくれませんでした。


取りあえず、意図した動きをしてくれたので、これでOK。


C-cm で起動時のサイズと場所に、C-cM で任意のサイズと場所に変更するようにしました。


なんか一冊読んでみたい気がしなくもない。

入門 GNU Emacs 第3版

Scheme マクロプログラミング ~基礎・応用~

みたいな本はないんでしょうか。日本語だと嬉しいんですが・・・。
On Lisp の Scheme 版みたいな。

scheme の「健全な(衛生的)マクロ」について基礎から詳しく書いてある書籍って、あるんでしょうか。見たことないし、聞いたこともない。ような気がします。あったら読んでみたいです。この際、R4RS でも・・・。

scheme の書籍でも、日本語の scheme 入門サイトでも、マクロはざっくり扱われている印象。
英語だと、濃そうなのは結構あるっぽい。

マクロの勘所は、あれこれ書いてみたり人のコードを読んだりしているうちに掴めるのかもしれません。ですが、なんというか、書籍1冊分くらいにまとまった量の情報を読みたいなーなどと思うわけです。。そういうのを読んで「へー!」とか「こういうふうに書けるのかー!」するのって楽しいんですよね。。

The Reasoned Schemer

syntax-rules: nth-value


多値を返す手続きから受け取った多値の n 番目を返すマクロ。


The Scheme Programming Language, 4th Edition