5.リスト処理
【length】
リストの要素数をカウントします。
lengthはAZ-Prologの組み込み述語として定義されているので、述語名をlist_lengthとしています。
1節目のlist_length述語は再帰終了条件です。
2節目で再帰処理、リストのカウントを行います。リストの要素がある限りは、2節目のlist_length述語で尾部を本体へ渡し再帰呼び出しをします。
※虚変数
今回2節目のlist_length述語では、頭部の第1引数のリストの先頭を「_(アンダースコア)」としています。 これは虚変数と言い、定義されていない変数となります。特に使用する必要のない値がユニフィケーションされるときなどに使います。虚変数の名前が「_.1」となっているのは、同一節に複数の虚変数が含まれていた場合に区別するために、出現順の番号を付与しています。
再帰を続けた結果、リストが[]になり1節目の述語とマッチし、本体へと移ります。
1節目の述語がマッチして初めてリストのカウントが始まります。
ユニフィケーションされた第2引数(N2)に1を足した値を(自分自身)の第2引数(N1)へユニフィケーションします。結果、sigma同様に再帰呼び出しされた値が順番に戻っていく過程でリストがカウントされ質問が成立します。→再帰呼び出しされた回数分、計算処理が行われリストのカウントが成立します。
【append】
第1引数のリストと、第2引数のリストを結合します。
appendはAZ-Prologの組み込み述語として定義されているので、述語名をmy_appendとしています。
1節目の述語は再帰終了条件です。空リストであれば、第2引数の要素を第3引数へユニフィケーションします。リストの要素がある限り、2節目の述語で再帰呼び出しを行います。
今回はリストを分解し、尾部を本体へ、頭部を第3引数へ渡しています。
Prologでは変数に1度値を定義すると再変更できません。
よって、my_append述語の第2引数は最初から最後まで値は変わりません。
再帰呼び出しを続けた結果リストが[]になり、1節目の述語とマッチしました。 そして本体に移ります。
前項同様に再帰の値が戻っていく過程で第3引数にユニフィケーションされた値が結合され成功します。
2節目の述語の頭部の第3引数を[A|Z]とすることで再帰をした値を1つずつ第3引数のリストの先頭へ追加しています。
【reverse】
リストの要素を逆順にします。
再帰する過程で本体の第2引数へ渡した値が頭部の第2引数へ渡ってることがわかります。
リストが[]になり、1節目の述語とマッチし、本体へ移りました。その結果、再帰によってユニフィケーションされた第2引数の値が第3引数へユニフィケーションされました。
2節目の reverse 述語本体の第2引数を[A|S]とすることで、要素を逆順にすることに成功しています。 Sの値をユニフィケーションされた順に頭部へ渡すことでリストが逆順になりました。
これを[S|A]にしてしまうと再帰の際に値がユニフィケーションされません。 リストの先頭にユニフィケーションしたい変数を置かなければいけないためです。
※先頭を無視して尾部へはユニフィケーションできません。
【member】
第1引数の値が第2引数のリスト内にあるか調べます
member は AZ-Prolog の組み込み述語として定義されているので、述語名をmy_memberとしています。
Xが2と1では一致しないため2節目の述語が呼び出されました。第2引数でリストを分解し尾部を本体の第2引数へ渡します。
本体へ渡された値が、1節目の述語と一致し、ユニフィケーションされました。
ここで第1引数の値が第2引数のリスト内にあることがわかりました。
【str2atomlist】
差分リスト。
空白を除き、二つの要素(atom)のリストにします
最初に第1引数のリストの文字列には空白がくるため3節目の述語で空白を除く処理を行います。
[32|L]とすることで、リストの先頭に空白が来た場合のユニフィケーションさせる条件を定義しています。
※空白のASCIIコードは[32]です。
このプログラムはQの右側が空リストとなって初めて値が決定します。
※ステップオーバーを利用すると操作が容易になります。