関数の定義
最初に,関数 pair-off およびその補助関数を,テキストにしたがって 定義します.テキストでは関数を直接に入力していますが, 関数定義を書いたファイルを作成して保存し,それをロードすることにします. その方がプログラムの編集が容易です. このプログラム(bugfix.lisp)を用意しましたので,以下のリンクから ダウンロードしてください. テキストでは second という補助関数を定義していますが, CLISP ではこの関数はすでに定義されています. そこで,my-second という関数名を使いました.
ダウンロードしたプログラムは,適当な場所(たとえば, ~/lisp/anderson/chap4/ の下)においてください.
Emacs のウィンドウが2分割され,下のウィンドウで CLISP が走っている とします.上側のウィンドウで bugfix.lisp を開いてください. 上側のウィンドウにカーソルがあるのを確認してから, C-x C-f で bugfix.lisp を開きます.
ファイル bugfix.lisp が開かれ, 上側のウィンドウに関数定義が示されます.
下側のウィンドウにカーソルを移動してから,bugfix.lisp を ロードします.
エラーから抜ける
リスト (a b c d) を引数にして,pair-off 関数を呼び出してください. 下側のウィンドウで (pair-off '(a b c d)) と入力して, Enter キーを押せばよいでしょう. ((a d) (b c)) というリストが返されればよいのですが...
CAR: A is not a list というエラーメッセージが表示され, ブレークループ状態に入りました. このエラーメッセージは,a を引数にして car が呼び出されたと 言っています.car の引数はリストでなければなりませんから, エラーになったのです.
ブレークループから抜けるには,:q と入力して Enter キーを 押します.
バックトレース
pair-off およびその補助関数の定義は簡単で,car は3か所で 使われているだけですから,どこでエラーが生じたのか 特定することはそんなに難しくありません. しかし,関数定義が少し複雑になると,エラーの原因個所の特定は かなりやっかいになることがよくあります.
このようなとき,バックトレースを使うと,エラー箇所の特定に 役立ちます. もう一度 (pair-off '(a b c d)) と入力してください.
ブレークループで :bt と入力して Enter キーを押してください. テキスト p.67 では (backtrace) という関数を呼び出しています. :bt コマンドはこれと同じです.
テキストで説明されているように,バックトレースは LISP が行った処理の一覧が表示されます.行われた処理の順序は, この一覧の下から上です.すなわち,EVAL frame for form (pair-off '(a b c d)) が最初です.これは (pair-off '(a b c d)) が 評価されたという意味です.
処理の一覧を上にたどっていくと,pair-off 関数の定義にある (LIST (OUTER-PAIR LIS) (INNER-PAIR LIS)) が評価され, さらに (INNER-PAIR LIS) が評価されていることがわかります.
最後に,(my-second y) が評価され,仮引数 y を '(a b c d) として, 関数 my-second の実行が試みられました.さらに, my-second の実行で,(car (car z)) が評価されています. ここでエラーが生じたのです.
ブレークループの中では仮引数に何が代入されたかを 調べることができます.(car (car z)) の z に代入された ものを調べるために,z と入力して Enter キーを押してください. (a b c d) というリストが表示されます.これが z に代入されたものです.