Shammer's Philosophy

My private adversaria

Clozure CL で load したファイルの返り値を受け取れるか

何らかの処理の書かれたファイルを読み込み、その返り値を受け取る、ということができないか試してみた。単純にloadしただけでは、ファイルのPATHが返されて期待した動作にならなかった。

? (defparameter x (load "/tmp/aaaa.lisp"))
X
? x
#P"/tmp/aaaa.lisp"
? (quit)

ちなみに中身は

(let ((a "100")) a))

となっていて、文字列の100が返されるようになっている。このファイルをwith-standard-io-syntaxで読み込みしても同じようにファイルのPATHが返される。

? (defparameter lll (with-standard-io-syntax (load "/tmp/aaaa.lisp")))
LLL
? lll
#P"/tmp/aaaa.lisp"
?

ファイルそれ自体を読み込み、その読み込んだものをwith-standard-io-syntaxで処理したらどうなるか。

? (with-open-file (file "/tmp/aaaa.lisp" :direction :input)
    (with-standard-io-syntax
      (setf lll (read file))))
(LET ((A "100")) A)
? lll
(LET ((A "100")) A)
?

これをfuncallしてみても関数形式じゃないと怒られる。

? (with-open-file (file "/tmp/aaaa.lisp" :direction :input)
    (with-standard-io-syntax
      (setf lll (read file))))
(LET ((A "100")) A)
? lll
(LET ((A "100")) A)
? (funcall lll)
> Error: (LET ((A "100")) A) is not of type (OR SYMBOL FUNCTION), and can't be FUNCALLed or APPLYed
> While executing: FUNCALL, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >

以下のようにラムダ式にすればfuncallできる。

? (funcall #'(lambda () (let ((a "100")) a)))
"100"
?

そのため、もとのファイルを

(lambda ()
    (let ((a "100"))
      a))

として、with-standard-io-syntaxで読み込んでみたが、これもダメ。

? (with-open-file (file "/tmp/aaaa.lisp" :direction :input)
    (with-standard-io-syntax
      (read file))))
(LAMBDA NIL (LET ((A "100")) A))
?
> Error: Reader error on #<CCL::RECORDING-CHARACTER-INPUT-STREAM #x302000FD419D>, near position 1:
>        Unmatched ')' .
> While executing: CCL::SIGNAL-READER-ERROR, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >

先頭に#'を付与して、funcallにいきなり渡すようにしてみたがそれもうまくいかない。

#'(lambda ()
    (let ((a "100"))
      a))
? (funcall (with-open-file (file "/Users/shimpei/aaaa.lisp" :direction :input)
    (with-standard-io-syntax
      (read file)))))
> Error: #'(LAMBDA NIL (LET ((A "100")) A)) is not of type (OR SYMBOL FUNCTION), and can't be FUNCALLed or APPLYed
> While executing: FUNCALL, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >

結局、うまくできたのはevalを使った場合だけだった。

? (with-open-file (f "/tmp/aaaa.lisp" :direction :input)
(do ((s (read-line f nil 'eof)
        (read-line f nil 'eof)))
    ((eql s 'eof))
  (format t "~A~%" s)))
(let ((a "100")) a))
NIL
? (eval (with-open-file (file "/tmp/aaaa.lisp" :direction :input)
    (with-standard-io-syntax
      (read file))))
"100"
?

evalを使ってまではやりたくない。このアプローチは使えないな。