Common Lisp

do ブロックの真似事

Node.js の勉強をしているときに気晴らしで書いたマクロ。ruby の do ブロック(元ネタがあるんだっけ?)をエミュレートする感じ。 (defmacro on (head &rest rest) `(|on helper| ,head ,rest ())) (defmacro |on helper| (head rest args) (if (null rest…

begin, recur, retry

オリジナル言語の新しい文法を妄想してやまないとき、継続や末尾再帰を使いたいなら Scheme で、それ以外なら Common Lisp でマクロなり何なりを書いて実験してみるのだけれど、実際にそうやって作ってしまうと、じゃあ新言語じゃなくてこれ使えばいいじゃん…

マクロで Ruby ライクな変数束縛をエミュレート

例えば…… (begin (= x 1) (= y 2) (begin (= x (+ x y))) (list x y)) という式で、最初の2つのイコールは let に変換され、3つ目は(たとえ入れ子になっていたとしても)すでに x が束縛されているので let ではなく setf に変換される。結果として (3 2)…

マクロを書き換えるマクロ

ちょっと思いついて、できるかなと思ってやってみたらできてしまったという類のアレ。とりあえずコード: (defmacro in-depth (&rest body) `(with-depth 0 ,@body)) (defmacro with-depth (depth-const &rest body) `(macrolet ((depth () ,depth-const) (i…

cxr, cxxr, cxxxr, cxxxxr の読み方

ずっと謎だった caar、 cadr、あるいはそれ以上に長いやつの発音が、この本の48ページ目(まえがきを入れると60ページ目)に書いてあった。 cadr はずっとカダーと読んでいたけど、正しくはキャットみたいにキャダーと読むべきなのか。まあ英語だとそうなる…

カリー化するマクロ

Paul Graham が開発したことで有名な Lisp 方言の Arc では、複合データを関数のように扱うことができるらしい。たとえば変数 s に文字列が入っていれば、(s 1) で1文字目を返す、とか。意味論的にどうなのかはともかく、いちいち (char s 1) と書きたくな…

let it B

CL-USER> (let ((it 'b 'e)) it) B なんてこった。

イテレータ生成メソッドと複合イテレータ

イテレータ・クラスのオブジェクトを作る、というのもやってみたけど、どうも無駄に仕様が大きくなっていくだけな気がしてすっきりしない。結局、Gauche が採用しているように関数オブジェクトで返すのが一番自由を感じられて良いのかな、と。それらを格納す…

代入マクロを書くマクロ

Common Lisp では、代入先の「変数」がシンボルであるとは限らないため、一般の代入マクロを書くには get-setf-expansion を使って情報を展開する必要がある。これを毎回やるのは面倒なので、マクロに肩代わりさせよう。 _f は『On Lisp』にあったものに少し…

制約関数

Prolog みたいに逆算できる関数というのを作ってみた。 引数のうちクエスチョンマークが置かれた部分の値を求める。すべての引数が数値で与えられたときは真偽を返す述語となる。 コード: (defparameter ? (gensym)) (defun ?-test (exp) (if (consp exp) `…

Common Lisp で遅延評価(part 2/2)

Common Lisp で遅延評価をやってみようという話の続き。1度ミスで消してしまって心が折れかけたよ。 さて、『計算機プログラムの構造と解釈』(SICP)にある、遅延ストリームで冪(べき)級数を扱ったりそれを微積分したりするという問題を解く。以下のコー…

Common Lisp で遅延評価(part 1/2)

『計算機プログラムの構造と解釈』(SICP)を読んでいる。いま Scheme インタプリタ再構築の章。近いうち、Common Lisp の上に実装して遊びたい。 今日の記事は、遅延評価を Common Lisp でやってみた、という話。delay & force も、マクロにかかればイチコ…

簡単な文脈自由言語パーサ&コンバータ

文脈自由言語を解釈して Lisp の式に直す、簡単なパーサとコンバータを作ってみた。きっかけは以下の記事。 最高にキモい Lisp コードを書いてみよう with 100 行リーダーマクロ(LISPMEMO) 自分でもできるんじゃないかと思ってやってみたら一応できた、とい…

リード・マクロ遊び

まずは否定関数の生成。 (defun |#~-reader| (stream subchar numarg) (declare (ignore subchar numarg)) `(complement #',(read stream t nil t))) (set-dispatch-macro-character #\# #\~ #'|#~-reader|) CL-USER> #~oddp #<Closure (:INTERNAL COMPLEMENT 0) @ #x2085f112> CL-USER> (funcall #~oddp 2) </closure>…

重複のあるオブジェクトを抜き出す関数

「重複を取り除くとか。」(http://d.hatena.ne.jp/narumij/20100603/1275527119) 重複のあるオブジェクトをそれぞれ1つずつ抜き出す関数。 やってみた! コード: (defun overlap (list &optional (test #'eql)) (labels ((rec (ls acc) (if (cdr ls) (if…

cl-ppcre と Allegro CL で、正規表現ツリーの出力が違った

題名のとおり。文字列で表された正規表現パターンをパースしてツリーにする関数がどちらにもあるのだが、まったく同じ出力をするのかと思っていたらこんな違いが。 CL-USER> (parse-string "ab") ; cl-ppcre "ab" CL-USER> (parse-re "ab") ; Allegro CL (:S…

文字列の中で式を評価、展開するリーダ・マクロ

Gauche では、Perl や Ruby と同じように、文字列の中で式を展開することができるらしい。 →文字列の補間(Gauche ユーザリファレンス) そこで、似たようなものを Common Lisp でやってみた。 コード: (defun concat-chars (ls) (if (null ls) nil (let ((…

loop マクロの変数キャプチャもどき

つい昨日知った機能。loop マクロの if, when, while では、テスト部分の値を it で参照できる。 この it は変数ではなく、あくまでも collect などと同じキーワードであるため、剥き出しで使わないと効果はない。 CL-USER> (defun trues (fn ls) (loop for …

後置演算マクロを定義するマクロ

後置インクリメントのような演算をマクロとして手軽に定義できるようにする、メタ・マクロ。 使い方は、3つの引数(定義するマクロ名、使用する演算名、第2オペランドのデフォルト値)を渡すだけ。演算名は単に貼り付けられるだけなので、マクロやラムダ式…

宣教師と人食い人の川渡りパズル

宣教師と人食い人の集団が川を渡ろうとしている。定員の決まっている舟を一艘だけ使える。岸でも舟の上でも、人食い人の数が宣教師の数を上回ってはいけない。さて、どうするか。 (cross m c b) で、m 人の宣教師と c 人の人食い人が定員 b 人の舟で渡る場合…

文字列をラクダ記法に変える関数と、そのためのユーティリティ

正規表現を使わないで書いたので、楽をするため、区切り文字列の判定は1文字のみ対応。デフォルトで lowerCamelCase になるのは私の都合。 position-all で区切り文字の位置をすべて求め、sequence-parts で部分列に分け、nstring-capitalize でそれぞれの…

麻雀の手牌が入力として与えられたとき、「待ち」を出力するプログラム

あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 ↑で出題されていた問題を Common Lisp で解いてみた。 最初の関数3つはユーティリティ。名前の通りで、条件を満たす要素すべての位置をリストにしたり、添字リストで nth して集めたり、…

迷路を解くアルゴリズム(改)

前回の迷路を解くアルゴリズムがほとんどCみたいで気にくわなかったので、より Common Lisp らしくなるよう書き換えてみた。 前と違って迷路内の点をそのまま (i j) という座標リストで表している。ユーティリティの裏に隠してあるので、意識する必要はない…

迷路を解くアルゴリズム

Common Lisp で書いてみた。 人材獲得作戦・4 試験問題ほか(http://okajima.air-nifty.com/b/2010/01/post-abc6.html) でもメモリ確保が簡単にできるということ以外は、ほとんどCで書くのと同じに……。 まず file-to-matrix でファイルから文字を読み取り…

ヒープによる優先度付きキュー(priority queue)

ちょっと思うところあって、優先度付きキューをヒープで書いてみた。ただし実体はクロージャ。引数なしで呼ぶとデキュー、引数を受け取るとエンキューするという単純なもの。 キューを作るためには、初期要素となる配列(未整列で良い)と順序関数を与える。…

ビット単位の入出力マクロ

ファイルの圧縮や展開をするときなど、ビットごとの入出力をしたいことは多い。そのためのマクロ。 with-gensyms は超有名ユーティリティ。 do-bits は do-list などと同じ使い方をする。変数名と入力用ストリーム(byte 系)を受け取って、ビットを順に変数…

リストで挿入ソート

リストって挿入に強いよな、と思って挿入ソートを書いてみた。速度重視で破壊的(rplacd とか久々に使ったよ)なのに再帰を使っているという矛盾。一応、リストの長さが10ぐらいまでなら組み込み関数の sort に勝っていた。100でやったらもちろん余裕で負け…

ツリーのイテレータ(幅優先)

このまえ深さ優先のトラバースを書いたので、今回は幅優先で。キューを使うので一手間ある。 コード: (defun make-queue () (list nil)) (defun enque (q x) (if (car q) (setf (cdr q) (setf (cddr q) (list x))) (setf (car q) (setf (cdr q) (list x))))…

関数のように振る舞うシーケンスをマクロで

arc という Lisp の方言では、シーケンスが関数のように振る舞うらしい。つまり s にシーケンスが束縛されているとすると、(s n) が Common Lisp における (elt s n) のようになる。 というわけで、同じことを Common Lisp でやってみた。 with-sequence は…

更新されない定数リストの落とし穴

この前、マスターマインドのプログラムを書いたときに遭遇したこと。 以下の関数 random-digits は、与えられた引数を長さとする数字の順列をひとつ返す。ただしバグあり。 CL-USER> (defun random-digits (num) ; wrong (do ((digits '(0 1 2 3 4 5 6 7 8 9…