COMMON LISP JP > Archives > 2019/11/14

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、とても楽しいです(∩´∀`∩)
2018/06/07 03:33:57 UTChojo
#
すっごい非効率なコードだと思いますが、なんとか読み込んだindex.lispに記述された複数のフォームをmapcarでぐるぐるevaluateStringすることができ、defmacroを利用することができるようになりました。
#
(global.jscl=require('jscl')).evaluateString(`
  (progn
    (defvar jscl (jscl::oget jscl::*ROOT* "jscl"))
    (defvar code ((jscl::oget jscl "evaluateString") (#j:String:prototype:concat "'(" (funcall (jscl::oget (require "fs") "readFileSync") "index.lisp" "utf-8") ")")))
    (mapcar (lambda (c) ((jscl::oget jscl "evaluateString") (write-to-string c))) code)
`)
2018/06/07 03:42:58 UTChojo
#
これから、ブラウザ側では<script type="text/x-common-lisp">CLコード</script> や <script type="text/x-common-lisp" src="外部CLファイル" /> でファイルを分けることで解決できないか試してみます!実は、一度試してみたのですが正しく動かず、サーバから静的ファイルのjscl.jsを配信する仕組みが無かったためjscl.jsをhtmlに無理やりねじ込む形を取っていたのですが、それが問題かなと思ってちゃんとしたテストができていませんでした!そこでこれからサーバ側からjscl.jsを取得できる仕組みを作り、まずは <script src="jscl.js" /> が機能するようにしてからようやくテストできそうです(∩´∀`∩)
2018/06/07 23:47:08 UTChojo
#
再びJSCLの質問になってしまうのですが、質問させてください><。文字列結合を行う際、#j:String:prototype:concat を利用していたのですが #jscl::concat が使えることがわかりました。しかし本来、Common LISPでは concatenate を使って文字列結合を行うことが多いようです。しかしJSCLのreplで concatenate を使うと ERROR: Function 'CONCATENATE' undefined と表示されて利用できないようなんです。試しにnodeのreplでjscl.CLにアクセスしてみたところ、内部的には concatenate がちゃんと定義されているようなのですが...なぜ利用できないのでしょうか??
2018/06/08 00:02:13 UTCshiro
#
ソースをざっとgrepしてみる限りでは定義されてないですね。シンボル自体はinternされてるんですが、boundされてないんじゃないですか。jscl.jsのシンボルのインターンをどこから持ってきたのか謎ですが(プリプロセスしてるCL処理系のCLパッケージを読み出してるのかな?)
2018/06/08 00:18:41 UTChojo
#
ご回答ありがとうございますm(_ _)m。なるほど、jscl.CL.CONCATENATEに実態のようなものがあるように思えたので、自分の使い方に誤りがあって使えないものだと思い込んでましたが、シンボルだけ用意されてて実際は使えないということだったんですね!この辺りはやはりまだ実装中ということになるんでしょうか。となると、他にも使えない関数が色々あるかもしれませんね( ;-`д´-)。大人しくjscl::concatを使わせていただきます!ありがとうございます!!
2018/06/08 00:40:13 UTCshiro
#
compileなどもシンボルだけあって実装がないので、これからってことだと思います。clパッケージにシンボルがあっても、fboundpとかsymbol-functionで調べた方が良さそうです。
2018/06/08 00:53:15 UTChojo
#
なるほど!fboundp なんて便利な関数があったんですね!知らなかったです!これで使えるか使えないか調べるのは楽チンですね(∩´∀`∩)。また、internについてもよくわからなかったのですが調べたら「インターンというのは、読み取り器(reader)で読み込んだ名前を大文字に変換して、シンボル表の中に同じ名前のシンボルがないかを調べる。シンボルが見つかったら、それを返す。見つからなかったら、新しいシンボルを作成してシンボル表に追加する。これら一連の作業のこと」という解説が出てきまして、前もってreaderの話など教えていただいてましたので色々と頭の中で話が繋がってきています!以前話に出た「cl:compileはシンボルが定義されてるけど関数定義が無いっぽい? 内部的にはjscl::compile-toplevelが CL->JS をやってくれるとこまでは確認できたが〜」という話は、そういうことだったんですね!少しずつ理解が深まってきました٩( 'ω' )و
2018/12/22 08:12:22 UTChojo
#
お久しぶりです!(気がつけばあれから半年も経ってますね)規格に準拠しているかどうかを点検するのに
#
おっと、Enterを押したら送信されてしまいました(失礼しました)

JSCLの理解を深める前に、自分自身がLISPの理解が浅いと言うこともあって、これからSchemeの実装を試みようと考えているのですが、自作した処理系がRnRSに準拠しているか確かめるプログラムというのは存在するのでしょうか?

また、そのような言語仕様を満たしているか検証するプログラムのことをなんというのでしょうか?検索したのですが見つけられなかったため検索ワードのヒントでもいただけないかと思いまして... アドバイスよろしくお願いします!
2018/12/22 08:17:49 UTCshiro
#
Schemeには厳密なもの/公式なものはないですが、R7RS smallの仕様を確認するtest suiteなら例えば: https://github.com/gypified/chibi-scheme/blob/master/tests/r7rs-tests.scm
2018/12/22 08:19:40 UTChojo
#
ありがとうございます!:)
2018/12/22 08:21:00 UTCshiro
#
R7RSはエラーの定義がゆるくて(処理系が独自に振る舞いを拡張してよい)、「エラーを出すこと」のテストがやりにくいんで、そこはカバーされてないですが。
2018/12/22 08:39:12 UTChojo
#
なるほど、そうなんですね!Schemeは比較的実装が簡単と聞いたので、どうせならJavaScriptで動くR5RSかR7RSに準拠した処理系を作ってみよう!あわよくばSRFIを乗せられたらいいな..とか思ってたんですが、エラーの定義がゆるくてもSRFIのような拡張を問題なく搭載できるものなのでしょうか?また、エラー定義が緩いというのはよくある言語のtry catch, throwなどの例外処理の定義が曖昧という解釈でよろしいですか?
#
今気がついたのですが、ここはCommon LISPの部屋でした(汗)別の部屋に移った方がよろしいでしょうか?
2018/12/22 08:53:48 UTCshiro
#
そうですね、Schemeについてもっと疑問があるならGauche部屋に移るのが良いかもしれません。
2018/12/22 16:19:07 UTChojo
#
ありがとうございます!Gaushe部屋で質問させて頂きますね!^^
#
×Gaushe ○Gauche