LISP Scheme

このエントリーをはてなブックマークに追加
546デフォルトの名無しさん
久々にネタ提供
いちいちrequire指定して外部ファイルを読みこませるのが
馬鹿らしくなったのでこういうの作ってみました。
外部ファイルを遅延ロードさせる関数です。
(関数が呼び出された時点でロードする。)

(define (ondemand fn sym-list)
  (define (regist s)
    (eval `(define-macro (,s . x)
             (if (require ',fn)
                 (cons ,s x)
                 (error "ondemand load failure" ',fn) ))
          (interaction-environment) ))
  (if (symbol? sym-list)
      (regist sym-list)
      (for-each regist sym-list) ))
547デフォルトの名無しさん:2001/08/04(土) 06:55
補足
・requireがマクロ→関数の上書きをしてくれないと機能しない。
・requireはloadでも代用できます。
・requireは 成功時#t 失敗時#f を返す実装であること。
これはロード中にエラーが発生した場合の対処。無くてもいい。
(requireでロードされるファイルに同名の関数が存在しないと無限ループになる。)

使い方
初期化ファイルなどに↓を置いておく
(ondemand 'trnscrpt '(transcript-on transcript-off))

こうすると、初期化ファイルが読まれた時点で仮のtranscript-on transcript-off
が定義される。
(transcript-on "log")
などとして関数を呼び出すと、そのときにtrnscrpt.scmを読みに行き、
transcript-on transcript-offが本来の関数にすげ変わり、その関数を再評価する。
548デフォルトの名無しさん:2001/08/04(土) 06:56
これでインタプリタの起動が数割程速くなりました。

問題点は、処理系依存な部分がありそうなんでどの環境でもそのまま動くとは限らない。
特に、ondemandで登録した関数は最初マクロとして定義されるので、
applyで呼び出されるとまずいかもしれない。(うちの環境では大丈夫だけど)
549デフォルトの名無しさん:2001/08/04(土) 07:05
あとclosureじゃないから、関数引数経由で評価される場合も
まずいかもしれない。
((lambda (p) (p "log") ) transcript-on)
とした場合。
550デフォルトの名無しさん:2001/08/04(土) 07:40
良く考えたら、普通の関数に対してはマクロ展開する必要は無いから、
仮関数を普通の関数にして、その中でapplyすれば解決する。
(define (ondemand-func fn sym-list)
  (define (regist s)
    (eval `(define (,s . x)
             (if (require ',fn)
                 (apply ,s x)
                 (error "ondemand load failure" ',fn) ))
          (interaction-environment) ))
  (if (symbol? sym-list)
      (regist sym-list)
      (for-each regist sym-list) ))

このondemand-funcを併用すれば、>>548-549で言われた問題が解決する。
(マクロの遅延ロードに対しては>>546を使う。)