COMMON LISP JP > Archives > 2018/06/05

2018/06/05 09:04:11 UTChojo
#
すみません、度々質問になるのですが、勉強のつもりでdefmacroを使ってjscl::ogetをogetでアクセスできるようにしてみよう!と思って以下のコードを実装してみたのですが、replだと上手くいくのにnode環境(evaluateString)では上手くいきません。
#
(defmacro oget (obj &rest names) `(jscl::oget ,obj ,@names))                                                                                                                         
(oget #j:Math "max")
#
Error: Function 'OGET' undefined
#
 もしかすると、defmacroもin-package同様、read時に行われる類のものなのでしょうか?
2018/06/05 09:44:56 UTCshiro
#
defmacroはread時ではなく、コンパイル時ですね。コンパイルと実行のタイミングの問題かな。
#
ところで、evalStringを2回やった場合、最初のevalStringで定義した変数や関数って2回目のevalStringから参照できますか? できるなら、最初のevalStringでdefmacroして次のevalStringでマクロ呼び出ししてみたらどうでしょう。
2018/06/05 10:09:43 UTChojo
#
const jscl = require('jscl')
jscl.evaluateString('(defmacro oget (obj &rest names) `(jscl::oget ,obj ,@names))')
jscl.evaluateString('(#j:console:log (funcall (oget #j:Math "max") 1 2 3))')
2018/06/05 10:13:44 UTChojo
#
上記コードを実行してみたところ、3という数字が出力されました!説明が不足していたのですが、二つ上のコードは外部から読み込んだlispコードを全て実行できるようにするためにprognをつけていたので、prognするのをやめてforeachなどでぐるぐる回しながらevaluateStringを呼び出したら上手くいきそうですね!ありがとうございます!
2018/06/05 10:48:18 UTCshiro
#
これブラウザ側で動かしてます? jsclのソース見てると、<script type="text/x-common-lisp">CLコード</script>とか <script type="text/x-common-lisp" src="外部CLファイル" /> でもいけそうな感じに見えるんですがどうでしょう。ひとつのscript要素の中のコードはprognで囲まれるみたいなんで、defmacroみたいにコンパイルフェーズ分けたいなら複数のscript要素にして。
2018/06/05 10:56:03 UTChojo
#
いえ、サーバ側で動かしていました!でも数時間前にブラウザでも動くようにしまして、ちょうどその部分どうなっているんだろうと思っていたので、思わぬ助言をいただけて良かったです\(^▽^)/ なるほど、<script type="text/x-common-lisp">CLコード</script>なんて使い方があったんですね!クライアント側でも、わざわざjscl.evaluateStringを呼んでました( ̄▽ ̄;) クライアント側で<script>タグで分けた時とそうでない時でdefmacroが使えるか使えないか試してみますね!
2018/06/05 10:56:38 UTCshiro
#
コード読んだだけで実際に動かしてみてはいないんですが。
2018/06/05 10:59:45 UTChojo
#
ところで、replのような対話モード以外でCommon LISPに触るの、恥ずかしながらほとんど初めてなのですが、JSCL以外の処理系でもファイルを読み込んでLISPを評価したりした場合、同じようにin-packageの問題やdefmacroが同じファイル上ですぐ使うことができないようなことって起こったりするのでしょうか?
2018/06/05 11:04:24 UTCshiro
#
ファイルは通常トップレベルフォームごとに読み込まれてコンパイルされるので、トップレベルに書いておくぶんにはokです。readの問題はファイルでもprognで囲んであったら生じます。defmacroについては規格でどうなってたか覚えてないんですが、処理系依存かも。clispではprognの中にdefmacroとマクロ呼び出しを置いても大丈夫でした。
2018/06/05 11:11:21 UTChojo
#
なるほど( ˘ω˘ )。ご丁寧な解説と確認までして頂いて、ありがとうございますm(_ _)m。確認なのですが「ファイルは通常トップレベルフォームごとに読み込まれてコンパイルされる」の「フォームごと」という部分は、(+ 1 2) (+ 3 4)みたいな2つの式書いたファイルを読み込ませた時に(+ 1 2)と(+ 3 4)ごとそれぞれ読み込まれてコンパイルされるという解釈をしたのですがこの認識で正しいでしょうか。
#
つまり、ファイルに書いた複数の式は、prognで囲ったように動作するが、実際は似て非なるものであるという解釈をしたのですが...
2018/06/05 11:25:15 UTCshiro
#
CLのソースは、readされ、compileされ、実行されます。シンボルのパッケージの解決とリーダマクロの展開はread時に起きます。マクロ定義の認識とマクロ呼び出しの展開はcompile時に起きます。残りのは実行時に起きます。これを把握してるとトラブルシューティングに役立ちますよ。
2018/06/05 11:39:26 UTChojo
#
なるほど!ものすごく重要ですね!!常識だとは思うのですが、知らなかった自分にとってはLISPによるプログラミングの混乱を大きく解消する一手と言える教えでした!!なるほど、リーダマクロの展開はread時に起こるのですね!(write-to-stringで出力したコードが自分の知ってるコードとは違ったのはまさかこれだったのか)気軽に質問ばかりして申し訳ないです!おそらくland of lispに記載してあることも読まずに伺ってるような気がしていますので、land of lispの読破についてもバックグラウンドで進めさせていただきます!!lisp、とても楽しいです(∩´∀`∩)