Common Lisp

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

関数 dft は、リストで表現されたツリーを受け取り、イテレータを作って返す。深さ優先でトラバースしながら、呼ぶたびに葉(リストでないもの)をひとつずつ返す。 (defun dft (tree) (let (stack) (labels ((rec (tr) (cond ((null tr) (rec (pop stack)))…

マクロを書くマクロのパズル

『On Lisp』から、関数やマクロの別名を定義するマクロ。 どれが正しいでしょう? (defmacro abbrev (short long) ; 1 `(defmacro ,short (&rest args) `(,long ,@args))) (defmacro abbrev (short long) ; 2 `(defmacro ,short (&rest args) `(,,long ,@arg…

Scheme 流のラベル付き let

Scheme の勉強をしていたら、つい。Scheme の let のように、ラベルを付けて再帰できるようにするマクロ。 separate-bindings は束縛リストを変数と初期値に分解するユーティリティ。 loop-let の使い方は、第一引数にラベル名を取る以外は let と同じ。この…

Common Lisp のリーダ・マクロであれこれ

リーダ・マクロの練習。全体的に Clojure を意識してみました。 ブレース({})は普通の丸括弧と同じ。 #{} はハッシュテーブルを作る。シャープとブレースの間に数を入れるとテスト関数を指定できる。 ブラケット([])はベクタを作る。引数は評価されない…

通常の順序で算術式を書けるようにするマクロ +α

最近読んでた本。 LISP〈1〉 (情報処理シリーズ) LISP〈2〉 (情報処理シリーズ) この2巻のほうで、通常の順序で書いた算術式を解釈する方法が解説されている。演習問題として単項演算を導入せよというのがあったので、やってみた。ついでに大小評価を連鎖で…

ベクタを関数に変換するマクロ

Clojure では、Common Lisp におけるベクタの表記みたいなものを使って匿名関数が作れるらしい。羨ましかったので、ちょっと真似してみた。 vector-to-lambda はベクタを見た目通りの関数にする。Common Lisp では縦棒で囲まれた部分がひとつのシンボルにな…

数独を解くプログラム

ふと思い立って、9×9の数独を解くプログラムを作ってみた。問題の数の配置はリストのリストで表現し(0の部分が空欄として扱われる)、関数 sudoku に渡すと勝手に解いてくれる。デフォルトでは解をひとつだけ見つける。オプショナル引数が2つあって、ひ…

(and (or null not endp) (or car first) (or cdr rest))

Common Lisp において、引数が nil かどうかを判定する述語が3つある。null と not はまったく同じ効果で、endp は引数がリストでないとエラー。 first と car や、rest と cdr も似たような立場にある。同じ効果で違う名前。 もっとも、同じ効果で違う名前…

エイト・クイーン、ついでに N-クイーン

エイト・クイーンを解くプログラムを Common Lisp で書いてみた。 関数 queen にボードのサイズ N を与えると、N×N のボードで N-クイーン問題を解く。 キーワード引数はふたつ。display に nil でない値を与えると、見つけたパターンをすべて表示する。base…

let の代わりに lambda の中でクロージャを作る

lambda 式の中で defun できるってことをいまさら知った。 CL-USER> ((lambda (x) (defun x+ (y) (+ x y))) 1) X+ CL-USER> (x+ 10) 11 CL-USER> ((lambda (x) (defun x+ (y) (+ x y))) 10) X+ CL-USER> (x+ 10) 20 CL-USER> #'x+ #<Interpreted Closure X+></interpreted>

組(tuple)を扱うためのユーティリティ

『On Lisp』の原著を半分くらいまで読んだ。とても面白い。プログラム自体もそうだけど、文章にも味があって。 さて、その本に載っていた do-tuple とその亜種のマクロがけっこう複雑で、コードを理解する前に自分で同じ動作のものを作ったりした、というの…

Clojure を勉強したい

Clojure の勉強をしたいけど、時間が……。とりあえずここを読んでみた。匿名関数が簡単に作れるのは嬉しい。あと関数名に関数オブジェクトが入っているのも。 関数定義で、引数の個数に応じて処理を分岐させられるというのは面白いし便利だ。というわけで Com…

クロージャをクラスみたいにしたかった

ふと、クロージャにクラスの性質があったら、と考えた。最初は Perl の bless を真似してみようかと思ったけど、参照数のコントロールができないとメモリリークを起こすような気がして、考えるのが面倒になった。そこで代わりにマクロを使って名前あり継承あ…

Iterator & Composite パターン

昨日に引き続き、デザインパターンの再現。今回は Iterator パターンと Composite パターン。コンポジットというのは要するにコンテナなんだろう、たぶん。集合体とでも訳せばいいのかな。 解説はコードの後。一応、以下のプログラムでは、イテレータの例と…

Observer パターン

Java の Observer パターンの一部を Common Lisp で再現してみた。わざわざオブジェクト指向にしなくてもいいなら、クロージャで済ませてしまうかもしれない。 (defclass observer () ((updater :initarg :updater :initform (error "updater must be suppli…

行列の積の計算をハードコーディング

行列の積を計算する式を直接ソースコードに貼り付けるために、プログラムを書いた。 make-matrix で作った行列ふたつを literal-product に渡して、文字のまま計算する感じ。【追記 2010-03-02】関数名がおかしかったのを修正 (defun row (m) (array-dimensi…

自由度の高めな関数合成マクロ

この前の pipe に似ているけれど、今度はその場で計算するのでなく、匿名関数を作って返す。 引数1は defun のようにパラメータ。引数2は関数の連鎖に渡される初期値となる。 キーワードは、:collect と :apply はそのまま。前者は多値をリストにまとめ、…

with-open-file の関数化

関数とファイルパスを渡して、with-open-file の中で処理をさせる。関数型言語の使い方が少し分かってきたような気がする今日この頃。 (defun safe-input (fn path) (with-open-file (ifile path) (funcall fn ifile))) (defun safe-output (fn path) (with-…

Common lisp でパイプ

シェルのパイプ機能ってとても便利だ。ruby などでメソッドをドットで繋げていくのも楽しい。ということで Common Lisp にてマクロでやってみた。 最初の引数が初期値で、その後ろに関数の名前(lambda 式でもいい)をずらずらと書いていく。キーワード :col…

完全二分木を作る関数

データ生成関数とノード数から、完全二分木(complete binary tree)を作る。 (defun make-cbt (fn size) (labels ((make-sub (i) (if (> i size) nil (if (> (* 2 i) size) (list (funcall fn i)) (nconc (list (funcall fn i) (make-sub (* 2 i))) (make-s…

let と lambda を相互変換

let と lambda がほとんど等価と聞いて。 ほとんど、というのは &optional, &rest, &key などパラメタ拡張表記を使わなければということ。たぶん。 (defun make-pair (ls1 ls2) "(a b c ...) + (1 2 3 ...) -> ((a 1) (b 2) (c 3) ...)" (if (and ls1 ls2) (…

Lisp コード内で、ダブルクオート以外の文字を使って文字列を表すリーダ・マクロ

Emacs などのエディタで、文字列の中のコードにも色を付けてもらいたい、あとバッククオートを文字列でそのまま使いたい、という動機から生まれた。 2つ以上連続する '' か、または改行。いろいろ改変可能。改行で終わらないようにすればヒア・ドキュメント…

一番外側に落ちた値を拾うマクロ

Common Lisp の対話モードでは、トップレベルで一番外側に落ちた評価結果がアスタリスクに格納されるようになっている。それをどこでも使えるようにしたかった。 ボディの前に局所変数となる名前をひとつ与える。これが外側に落ちた値を拾う。let のように括…

素因数分解パッケージ

習作。素数判定や、多倍長整数の素因数分解をする。 ;; Package for math problems about prime numbers (defpackage :math.prime (:use :common-lisp) (:export :primep :factor :afactor)) (in-package :math.prime) (defparameter *primes* (make-array 2…

Lisp で四則演算を普通の順序に

いわゆる再帰下降パーサ。『C言語による最新アルゴリズム事典 (ソフトウェアテクノロジー)』の「式の評価」の項を、ページに開き癖がつくほど参考にした。 一応、シンボルは書いた順序どおりに評価されるはず。 単項演算の(つまり符号反転の)マイナス記号…

単機能ベンチマーク

繰り返し回数を決めて、時間を測るだけというストイックさ。そのくせ複数フォームを渡せるという無駄仕様。 (defmacro benchmark (times &body body) (let ((gi (gensym))) `(progn ,@(mapcar #'(lambda (form) `(progn (print ',form *trace-output*) (time…