Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-04-19

FORMAT指示子を自作関数で理解する試み

| 21:51 | FORMAT指示子を自作関数で理解する試み - わだばLisperになる を含むブックマーク はてなブックマーク - FORMAT指示子を自作関数で理解する試み - わだばLisperになる

FORMAT関数は便利なのですが、指示子の引数の扱いが全然暗記できないので、せめて良く使う~Aだけでもマスターしたいと思い記憶できるような方法をあれこれ考えてみました。

まず、~Aには、~Aと~@Aがあるのですが、日本語版のCLtL2では「文字列は右に詰められる(もし@修飾子が用いられるのであれば左に)」という記述です。

これだと、~Aは右詰めかと思うのですが、原文は、The string is padded on the right (or on the left if the @ modifier is used) with at least minpad copies of padchar.とのことで、右側がパディング文字で埋められた文字列、つまり、結果としては、日本語でいう左詰めになるというややこしさ。

面倒なので~Aは左詰め、~@Aで逆転、とおぼえることにします。

とりあえず、@の役目は暗記できたので、次に引数です。

説明を読んでも理解できないので、~Aと同じ動作をする関数を作ってみました。

(defun A (s arg &rest params)
  (destructuring-bind
        (&optional (mincol 0) (colinc 1) (minpad 0) (padchar " ")) params
    (let ((pad (max 0 minpad (- mincol (length arg)))))
      (princ arg s)
      (loop :repeat (* pad colinc) :do (princ padchar s)))))

(format t "~@{~10,1,10,'*A~}" "foo" "bar" "baz")
;>>> foo**********bar**********baz**********

(format t (lambda (s &rest args)
            (dolist (x args) ; ~@{ ... ~}
              (A s x 10 1 10 "*")))
        "foo" "bar" "baz")
;>>> foo**********bar**********baz**********

CLtL2の内容をコードに起したつもりではあるのですが、もしかしたら間違ってるかもしれません。

まあ、でも各引数の意味は理解できました。

それで、引数は省略できるのですが、省略にも順序があって、

;; 4つ全部
(format t "~99,88,77,'*A" "foo")

;; 3つの場合
(format t "~99,88,77A" "foo")(format t "~99,88,77,' A" "foo")

;; 2つの場合
(format t "~99,88A" "foo")(format t "~99,88,0,' A" "foo")

;; 1つの場合
(format t "~99A" "foo")(format t "~99,1,0,' A" "foo")

;; 0
(format t "~A" "foo")(format t "~0,1,0,' A" "foo")

という右から順番に省略されたことになります。自作の関数も&restと&optionalの組み合わせで再現してみました。

それで、引数の順番ですが、ここは丸暗記です。

mincol、colinc、minpad、padcharという並びですが、min-col-inc、min-pad-charと結合して無理に憶えたいと思います。ちなみに、~Dでは、また別の並び方をしています…。

まだまだ複雑怪奇な指示子は沢山ありますが、自作してひとつずつ理解していくというのも、まあまあ、アリかなと…。

Arcの述語のネーミングルール

| 19:03 | Arcの述語のネーミングルール - わだばLisperになる を含むブックマーク はてなブックマーク - Arcの述語のネーミングルール - わだばLisperになる

古典的なLISPだと-P、Schemeだと-?を末尾に付けると述語になるというのが何となくの慣習。

Arcだと、a-という風に頭に、aがつくのが多い。acons、alist等。

symmetricという場合を考えてみるにsymmetricp、symmetric?はOKだけど、asymmetricでは非対称という正反対の単語になってしまう。

こういう場合はどうしたら良いのだろう。

ArcでL-99 (P56 二分木が線対称な構成かを調べる)

| 18:59 | ArcでL-99 (P56 二分木が線対称な構成かを調べる) - わだばLisperになる を含むブックマーク はてなブックマーク - ArcでL-99 (P56 二分木が線対称な構成かを調べる) - わだばLisperになる

バックトラックをどうしようか、と考えていたら全然進めなくなったので、それは置いておいて、まずは普通にリスト操作で解いて後で考えることにしました。

後ではやらない可能性もありますが…(笑)

mirrorという補助関数を定義して解いてみよう、ということなので、反転して同じ構成かを比較しろ、ということなのかと思い、そういう風に書いてみました。

個々の葉の要素が同じかではなく、構成が同じかどうか、ということなので、skeltonという構成をコピーする関数を定義して比較しています。

(symmetric? '(x nil (x (x (x nil nil) (x nil nil))
                       (x nil (x nil nil)))))
;=> nil

(symmetric? '(x (x (x (x nil nil) (x nil nil))
                   (x nil (x nil nil)))
                (x (x (x nil nil) nil)
                   (x (x nil nil) (x nil nil)))))
;=> t

(def mirror (tree)
  (if no.tree
      ()
      (let (rt l r) tree
        `(,rt ,mirror.r ,mirror.l))))

(def skelton (tree)
  (if no.tree
      ()
      (let (rt l r) tree
        `(x ,(skelton l) ,(skelton r)))))

(def symmetric? (tree)
  (let skel (skelton tree)
    (iso skel (mirror skel))))