「Ansi Common Lisp」12章読了
データの構造と題して、なんか抽象的な感じ。
共有構造
「あるリストが別のリストの一部」である状態を指すらしい。
* (setf part (list 'b 'c)) Warning: Declaring PART special. (B C) * (setf whole (cons 'a part)) Warning: Declaring WHOLE special. (A B C) *
「あるリストが別のリストの一部」であるかどうかを検査するには、tailpを使う。
* (tailp part whole) T * (tailp '(b c) whole) NIL *
書き換え
共有部分を書き換えると、両方のリストに影響しますよ。という至極当たり前の話のようです。
* (setf (second part) 'd) D * part (B D) * whole (A B D) *
これが意図しない場合は、コピーを作って操作するとか、そもそもsetfみたいな副作用の伴う処理をしないのが良いのだそうです。
破壊的関数
たとえば、deleteはremoveの破壊版であり、引数として渡されたリストを破壊してよいことになっているが、書き換え内容に関する保証はない。
で、載っているサンプルを動かしてみる。
* (setf lst '(a r a b i a)) Warning: Declaring LST special. (A R A B I A) * (delete 'a lst) (R B I) * lst (A R B I) *
lstが(R B I)になっているかと思いきゃ、(A R B I)になっているというワナ。副作用もよく動作を理解して使わないといけないってことですね。
循環構造
リストのcdr部に自分自身を設定するとできるらしい。
* (setf x (list 'a)) (A) * (progn (setf (cdr x) x) nil) NIL * x (A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A ...
大域変数*print-circle*をtにすると、循環構造用の形式で表示される。
* (setf *print-circle* t) T * x #1=(A . #1#) *
これ、他の言語でもできるのかやってみた。
まずはRuby。
lst = [1,2,3] lst << lst print lst
結果はこう。
123123[...]
[...]ってのが循環表記なのか?
次Java。
import java.util.*; public class loop { public static void main(String[] args) { List x = new ArrayList(); x.add("a"); x.add(x); System.out.println(x); } }
結果はこう。
[a, (this Collection)]
今度は(this Collection)だって。なんかちゃんと考えられているのね。
次、JavaScript。
<script language = "JavaScript"> lst = ["a"]; lst[1] = lst; alert(lst); alert(lst[1][0]); </script>
結果はこう。
a, a
循環構造に対して特別な出力はしないようですが、構造としてきちんと扱えていることは確認できますね。
Lispのデフォルトみたいに循環構造をprintすると暴走するような言語はなさそうです。
本書中ではバッファやプールを表現するのに役に立つことがあると書いてあるので、そういうシーン(なさそうですが。。)になったら思い出そう。
定数的データ構造
定数的データ構造とは、'(a b c d)みたいなやつのことらしい。
戻り値として定数的データ構造を戻す関数があったとして、戻り値に副作用を加えると、関数の挙動が変わってしまうという話。
* (defun arith-op (x) (member x '(+ - * /))) ARITH-OP * (nconc (arith-op '*) '(as it were)) (* / AS IT WERE) ; -------------------------------------------------- ; この時点で、arith-opの中身は、(member x '(* / as it were))に変わっている ; -------------------------------------------------- * (arith-op 'as) (AS IT WERE) *