Common Lispの系譜を継ぐマイコン上のuLispをラズパイPico2上で練習中。このところCommon Lisp上とuLispで実装が違うものどもを調べてます。今回はローカル変数を利用するためのものども、let(Special Form)やdo(Macro)などの一族です。この辺は実装は違えど挙動は同じじゃ。
※Lispと一緒 投稿順 index はこちら
※実機確認は Raspberry Pi Pico2で行ってます。
※使用させていただいとります uLisp のバージョンは 4.6b (Arm用)です。
※uLispとCommon Lispとの動作比較のために使わせていただいている処理系は以下です。
SBCL 2.2.2 (SBCL = Steel Bank Common Lisp )
今回の動作確認リスト
今回、実機上で動作確認してみるのは以下の6つです。
-
- let
- let*
- do
- do*
- dolist
- dotimes
let、let*はCommon LispではSpecial Formですが、uLisp上では他のSpecial Formどもとはかなり形が異なる、でもSpecial Form的な実装デス。一方、do以下の4つはCommon LispではMacro、uLispでは普通のSpecial Formです。
let、let*は局所変数を作り、その有効スコープを定めるもの。do一族は繰り返し構造を作り、その中で局所変数を有効にするやつらです。
letとlet*
呼吸をするようにS式が出てくる姉貴、兄貴の皆さま方に、letとlet*の違いなど説明する必要はありますまい。Lisp素人老人があえて書けば、局所変数の初期化の仕方が違うと。letは並んでいる局所変数を見掛け「同時」に初期化するので、初期化で何か変数など参照している場合はletの外側のものどもが参照されるハズ。一方 let* は、局所変数を並びの順で順番に初期化していくので、後の変数の初期化に前の変数を参照することが可能っす。
上のletの中の局所変数 yの初期化で参照されているx(緑)は、その外側で定義されている大域変数 x(緑)であります。よって結果は125だと。
一方let*の中の局所変数 yの初期化で参照されているx(赤)は、その前方の局所変数x(赤)です。よって結果は3だと。
結果は同じだ。よかった。
doとdo*
さて、doとdo*は、多分マクロ内部でletとlet*を利用しているのだと思いますが、ループを作りだし、その内部で局所変数を使えるようにしてくれるものです。他のプログラミング言語でよくある for みたいな感じ。複数の局所変数それぞれについて、初期値とループを回る度の更新値を与えることが可能。また終了条件と戻り値の定義もできると至れり尽くせりの構造です。
先のletとlet*同様、初期化時の挙動の違いで、doとdo*があり。殊更に作った処理例が以下に。まずはCommon Lisp。
doとdo*の違いだけで、返るリストは違いますな。あたりまえか。
これまた結果は同じだ。よかった。
dolistとdotimes
Lisp素人がざっくり言ってしまうと dolist は他の言語の foreach、dotimes は一番単純な回数だけのループっす。ちょっとLispがカッコイイのは、戻り値が指定できる(指定しないとNILが返る)ところです。
ことさらな例がこれまた以下に。まずはCommon Lisp。
dolistとdotimesで同じことをやってみましたぜ。当然結果も同じ。
やっぱり結果は同じだ。よかった。