COMMON LISP JP > Archives > 2018/09/25

2018/06/03 22:51:56 UTChojo
#
なるほど!ご丁寧な解説ありがとうございます。つまり、jscl-repl環境で期待通りの動作をしたのは、対話する毎にreadされ、その度にin-packageが解釈されるから問題なく動作した。しかしevaluateStringの中で評価したコードは全てのコードが1度でreadされるため、うまくいかないということになるのでしょうか。
2018/06/03 22:53:03 UTCshiro
#
その解釈で合ってます。
2018/06/03 22:54:34 UTChojo
#
なるほど、確かにお話を聞いてるとclをコンパイルする方法でやった方が良さそうですね..(´・ω・`;)。すみません!なんとなくjscl::ogetと書くのが長ったらしく感じてしまったのと、jscl::ogetのようにコロンを二つ並べてアクセスするのは、あまり良くないという文章をどこかで見たので、安易な気持ちで取り組んで見たのですが、どうやら底が深い問題だったようです( ̄▽ ̄;)
#
もう一度頭の中を整理して見ます!貴重な情報と対応に本当に感謝ですm(_ _)m
2018/06/03 23:04:12 UTCshiro
#
というか::で内部シンボルにアクセスするのは良くないっていうのは、モジュールの内部に手を突っ込んでるからです。(in-package :jscl)するのはモジュールの中に入り込んじゃうことですから良くなさで言えばもっと良くない :-) もちろんモジュール自体を改造する意図なら別ですが。どっちかというと、ogetがexportされてないんだったら他の公的な方法があるはずだからそれを探す方がベターな気もしますが… tests/ffi.lispのコメント見る限り、ogetとかをexportするのはまだこれからだから今はjscl::でアクセスするしかなさそう。
2018/06/03 23:23:23 UTChojo
#
なるほど!(in-package :jscl)のはもっと良くない方法だったんですね(^_^;) 大人しくjscl::を付けてプログラミングすることにします!ありがとうございます!
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、とても楽しいです(∩´∀`∩)
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 をやってくれるとこまでは確認できたが〜」という話は、そういうことだったんですね!少しずつ理解が深まってきました٩( 'ω' )و