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 回答