Common Lispの系譜を継ぐマイコン上のuLispをラズパイPico2上で練習中。これまでの練習中に既に何度となく使ってしまった関数の定義 defun と大域変数の定義 defvar です。しかし、改めて見てみると Common Lisp と uLisp の挙動にコマケー違いがあることに気づきました。知らないとツボる?
※Lispと一緒 投稿順 index はこちら
※実機確認は Raspberry Pi Pico2で行ってます。
※使用させていただいとります uLisp のバージョンは 4.6b (Arm用)です。
※uLispとCommon Lispとの動作比較のために使わせていただいている処理系は以下です。
SBCL 2.2.2 (SBCL = Steel Bank Common Lisp )
今回の動作確認リスト
今回、実機上で動作確認してみるのは以下の3つです。
-
- defun
- defvar
- quote
いずれも基本中のキホン、避けて通れないものどもです。なお過去回で quoteは、(quote …のような「正式な」書き方はせず、’… みたいな略記法(なんといったらよいのか、Lisp素人老人は困った)で書いてました。
defun
defunは関数定義のマクロ(Common Lisp上では。uLispでは例によってスペシャルフォーム)です。Lispに精通された姉貴、兄貴の方々には説明の必要ないかと思いますが、Lisp素人老人が説明するとこんな感じです。
(defun 関数名 (パラメータ…) 関数処理の本体)
まあ、CやPythonなどで関数定義するときとさほど大きな差はない?
しかし、Common LispとuLispでちょいと挙動が違うことに気づいてしまいましたぞ。まずはCommon Lisp。
普通に、plus3などというベタな関数を定義して、呼び出してみてます。結果は予定通り。しかし、同じ感じで log というお名前で関数定義しようとしたら上のように警告がでます。log はね、自然対数を得る関数として処理系が既にもっている関数です。そんな大事なものを上書きするのか、コラ!という感じ。
上記のようにCommon Lispでは警告がでてデバッガに落ちます。そこでABORTを選択すれば定義されることはなかったです。しかしCONTIMUEを選択すると「定義できちゃった」ように見えました。しかし実行してみたら、何やらエラーとなってます。
問題の「log の再定義」のところ、警告も何も出力されず、フツーに定義できたように見えます。しかし、関数として呼び出してみると元からある関数が呼び出されて結果が返ってきているみたいです。多分メモリ上では新旧仲良く共存しているけれども呼び出されるのは先に定義されている元からある方なのではないかと想像。uLispの場合、不用意に命名した関数が「被った」お名前だとビックリする挙動を示すかもですな。忘却力のLisp素人老人は注意しないと。
defvar
defvarは大域変数を定義(宣言)するためのマクロです。過去回でやりましたが、Common Lispでは、defvarせずにsetqで変数に値を代入しても許してくれていましたが(過去のしがらみ?知らんけど)、uLispでは setqの前にdefvarで変数を宣言しておかないとエラーになります。
Lisp素人老人に見える defvar はこんな感じです。
(defvar 変数 初期値を与える式)
この初期値の部分の扱いに「個性」が出てしまっていることに気づきました。
それ以前に存在ない変数xをdefvarした初回では初期値3が与えられていますが、同じ変数xを再度defvarしたときは初期値999は「捨てられて(評価されない)」ます。どうもこの「既に変数が値を持っている場合は初期値を与える式は評価されない」というのが正しい動作みたいです。宣言後は setq で値を与えることが可能です。
defvarする度に値が書き換わっているじゃん。。。コマケー違いということで良いの?
quote
quoteについては差は見えなかったです。まずはCommon Lisp。
ここは平穏無事でよかった。