2012-01-06 8 views
5

標準の共通-lisp関数/マクロを使ってパッケージから現在のパッケージにいくつかの関数を一時的にインポートする方法はありますか?Common Lisp:パッケージからいくつかの関数を一時的にインポートするための最良の方法

私は1つを見つけることができず、自分自身をロールバックしなければならなかった。標準が既にそのような機能を提供しているならば、何かをコード化する必要はなく、別の言語構造を導入する必要はありません。

(defmacro with-functions (functions the-package &body body) 
    "Allows functions in the-package to be visible only for body. 
    Does this by creating local lexical function bindings that redirect calls 
    to functions defined in the-package" 
    `(labels 
    ,(mapcar (lambda (x) `(,x (&rest args) 
           (apply (find-symbol ,(format nil "~:@(~a~)" x) 
                ,the-package) 
             args))) 
       functions) 
    ,@body)) 

使用例:

(defclass-default test-class() 
    ((a 5 "doc") 
    (b 4 "doc"))) 
#<STANDARD-CLASS TEST-CLASS> 
CL-USER> 
(with-functions (class-direct-slots slot-definition-name) 'sb-mop 
    (with-functions (slot-definition-initform) 'sb-mop 
    (slot-definition-initform 
     (car (class-direct-slots (find-class 'test-class)))))) 
5 
CL-USER> 

EDITは:マクロにライナーの提案の一部を組み込みました。

私は、パッケージ内の関数を見つけるために、実行時のルックアップの時間コストで、実行時のルックアップ機能を維持することを決めました。

私はシャドウイングインポートおよびuninternを使用して、インポートマクロを書き込もうとしましたが、私はそれが仕事を得ることができませんでした。私は読者に、関数をインポートしたコードが評価される前に、インポートされた関数が(読み込み時に)まだ存在していないと言う問題がありました。

シャドウイングとアンインンターンで動作させる方が良い方法だと思います。これははるかにクリーンで速く(実行時ルックアップ機能はありません)、パッケージ内の関数とシンボルで動作します。

誰かがuninternとshadowing-importを使ってimport-withマクロをコード化できるかどうかを知りたいと思うでしょう。

+0

このAPPLYは記号を名前として使用して呼び出すことができないため、字句関数では機能しません。 –

+0

マクロを展開する前にシンボルが読者によって解決されているので、これはマクロでは可能ではないと思いますが、私は間違っているかもしれません。 – Daimrod

+0

@Daimrodこのようなマクロを構築することは可能ですが、初期のシンボル解決戦略に起因する名前の競合を処理する必要があるため、非常に扱いにくい(おそらく、移植性がない)場合があります。 –

答えて

1

あなたがそれらをインポートして、uninternたい資格のシンボル(すなわちpackage:symbolまたはpackage::symbol)のリストをimportを使用することができます。

2

これは、ランタイム関数は、はるかに高価な呼び出しを行います、それは引数リストをコンスパッケージ内のシンボルを検索し、シンボルの関数セルを介して関数を呼び出します。

シンボルのみで動作し、字句関数では動作しません。これは、コードがマクロを介して生成される場合にはあまり役に立ちません。

名前が混乱しています。 'import'はパッケージ操作であり、パッケージはシンボルだけを処理し、関数は処理しません。パッケージ内の関数はシンボルとしてインポートすることはできません。

(labels ((foo() 'bar)) 
    (foo)) 

字句関数名FOOは、ソースコードシンボルです。後でそのソースシンボルを介して関数にアクセスする方法はありません(たとえば、(symbol-function 'foo)を使用して)。コンパイラが上記のコードをコンパイルする場合、シンボルを保持する必要はありません。デバッグの目的以外では必要ありません。 APPLYへの呼び出しは、LABELSまたはFLETによって作成された関数を見つけることができません。

マクロはシンボルをインポートしません。ローカルのレキシカル関数バインディングが作成されます。少し似てマクロの

CL:WITH-SLOTSCL:WITH-ACCESSORSを参照してください。ランタイムルックアップはサポートしていませんが、効率的なコンパイルが可能です。

あなたのマクロは、このような巣が(ここではちょうどあなたの "SB-MOP" のように、パッケージとして "CLOS" を使用して)いません:

(defpackage "P1" (:use "CL")) 
(defpackage "P2" (:use "CL")) 

(with-import (p1::class-direct-slots) 'CLOS 
    (with-import (p2::class-direct-slots) 'P1 
    (p2::class-direct-slots (find-class 'test-class)))) 

生成されたコードは次のとおりです。

(LABELS ((P1::CLASS-DIRECT-SLOTS (&REST ARGS) 
      (APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'CLOS) ARGS))) 
    (LABELS ((P2::CLASS-DIRECT-SLOTS (&REST ARGS) 
      (APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'P1) ARGS))) 
    (P2::CLASS-DIRECT-SLOTS (FIND-CLASS 'TEST-CLASS)))) 
+0

ユースケースの理解に問題があります。 '関数'のarglistには ':'があってはいけません。関数arglistには関数名を表すシンボルがあり、パッケージにはこれらの関数が存在します。これはwith-slotsとwith-accessorsに似ています。私はあなたが書いたコードは次のようになるはずだと思います:(with-import(class-direct-slots) 'clos(クラスダイレクトスロット(find-class'テストクラス))) –

+0

@claytontstanley:どうしてですか? p1 :: class-direct-slotsは法的な関数名です。 WITH-SLOTSまたはWITH-ACCESSORSは、そのような名前を扱うのに問題はありません。私の例では、ある関数が生成され、次にそれを使用しようとする別のWITH-IMPORTがあなたのマクロでは不可能であることを示しています。覚えておいてください:Common Lispマクロを扱う場合、単純な方法でエンドユーザが使用する構造体を記述するだけでなく(その制限を文書やチェックする必要があります)、すべてが多くの部分になることもあります他のコード( - >マクロ)によって生成されるより複雑なコード。 –

関連する問題