FrontPage
New
Tools
Index
TempPage
Edit: [Lisp処理系を作る] 03日目 NIL を作る
本当は List と一緒に作りたかったのだが、かなり複雑だったので独立してみる。 !!! nil の特徴 * List である ** car cdr 共に nil を返す * Atom である * Symbol である ** それには nil が 束縛 されている ** "nil" という名前を持っている。 xyzzy では以下は全部 t を返却する。 8< (listp nil) (null (car nil)) (null (cdr nil)) (atom nil) (symbolp nil) (boundp nil) (null (symbol-value nil)) >8 こうなってくると、 nil は各オブジェクトの特殊な場合を指すような気がしてくる。 うーむ、多重継承が欲しくなってくる。 !!! どう実装するか? * ISymbol インターフェイスを用意する。 ** string Name { get; } ** SymbolicExpression Value { get; } ** void Bind( SymbolicExpression s ); ** void Unbind(); * List インスタンスの car cdr 共に nil の場合を nil とする。 * List で ISymbol を実装する。 nil でない場合は例外を投げ、 nil 場合はそれに沿った処理をする。 * Atom を継承し ISymbol を実装して Symbol クラスを作成する。 * SymbolTable は ISymbol を操作するクラスにする。 ** Nil に関する動作は SymbolTable で頑張ることにする。 これにより * 空リストを nil とすることが出来る。 * List インスタンスの nil に対して List 操作と Symbol 操作が行える * Symbol インスタンスの nil に対しては List 操作を行えないので工夫する必要がある。 ** SymbolTable で頑張れば回避可能かも。 !!! NIL 定数を作る List の特殊なインスタンスを NIL とするので List クラスの static readonly な変数を用意する。 8< public class List : SymbolicExpression, ISymbol { public static readonly SymbolicExpression NIL; static List() { List nil = new List(); typeof( List ).InvokeMember( "car", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance, null, nil, new object[]{ nil } ); typeof( List ).InvokeMember( "cdr", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance, null, nil, new object[]{ nil } ); List.NIL = nil; } : } >8 * 通常 List クラスはコンストラクタで引数なしだと car と cdr に定数 NIL を入れておく。 * この記述中の static コンストラクタ内では 定数 NIL には null が入っている。 ** この時に List インスタンスを作ると car cdr には null が入ってることになる。 * とりあえず List インスタンスを作る。 * そこに無理矢理リフレクションを使って car と cdr に自身を代入している。 ** List クラスの car と cdr は readonly なので通常の代入は出来ないから。 !!! 次の日 [[[Lisp処理系を作る] 04日目 Symbol を作る]]
Administrator's Sign:
freeze
Attachment
New:
Rename
Title:
Administrator's Sign: