5

「ip」、「date」、「url」などの名前の関数のセットがあります。

これらを使用して、「ip-is」、「date-is」などの別の関数セットを生成したいと思います。

私はついに次の解決策を手に入れました。それはうまく機能していますが、それは「eval」を使用しています。

(loop for name in '(ip date url code bytes referer user-agent) do
  (let ((c-name (intern (concatenate 'string (symbol-name name) "-IS"))))
    (eval `(defun ,c-name (c)
           #'(lambda (l) (equal (,name l) c))))))

誰かが私を助けてくれますか、「邪悪な評価」を取り除く方法は?私のプログラムでは、関数名がリストとして提供されていることが不可欠です。だから、いくつかのマルクロへの呼び出し

   (define-predicate ip)
   (define-predicate date)
   (define-predicate url)

私のニーズに合わないでしょう。「eval」については特に問題はありませんが、evalは悪いスタイルと見なされており、可能であれば避ける必要があることをよく読んでいます。

前もって感謝します!

4

2 に答える 2

7

ここではマクロを使用する必要があります。マクロはコンパイル(またはロード)中に評価され、プログラムで関数定義を生成するために使用できます。コードは次のように書くことができます:

(defmacro define-predicates (&rest names)
  `(progn
     ,@(loop
          for name in names
          collect (let ((c-sym (gensym))
                        (l-sym (gensym)))
                    `(defun ,(intern (concatenate 'string (symbol-name name) "-IS")) (,c-sym)
                       #'(lambda (,l-sym) (equal (,name ,l-sym) ,c-sym)))))))


(define-predicates ip date url)

シンボルはGENSYM関数でを使用して生成されることに注意してください。この特定のケースでは、これは厳密には必要ありませんが、後の段階でコードをリファクタリングした場合にリークが発生する可能性がないように、通常はこの方法で行うことを好みます。

于 2013-02-10T16:34:54.477 に答える
5

(他の答えのようなマクロの代わりに)関数を使用したい場合は、以下を使用する必要があります(setf fdefinition)

(loop for name in '(ip date url code bytes referer user-agent) do
  (let ((c-name (intern (concatenate 'string (symbol-name name) "-IS"))))
    (setf (fdefinition c-name)
          (lambda (c) (lambda (l) (equal (funcall name l) c))))))
于 2013-02-10T18:27:56.363 に答える