Eval in Common Lisp

时间:2012-12-09 04:10:21

标签: functional-programming lisp eval common-lisp


我是lisp的新手,这是我的问题:
我有一个类似

的列表
((a ((length 3) (size 5))) (b ((length 5) (size 7))))...

以上列表只是一个示例。
我想要的是一个函数find,它可以像数据库查询一样工作,例如

(find (and (gt length 4) (lt size 8)))

在这种情况下,上面的函数应该为我找到b。请注意,此函数的条件参数可以使用andor进行扩展...
我做了一些研究,并知道eval能以某种方式帮助我,但我不确定它是如何运作的。
有人可以给我一个例子,或者给我一些暗示?

谢谢

2 个答案:

答案 0 :(得分:4)

我不会为此使用eval。但这样做会相对容易。

您有一系列项目:

((a ((length 3) (size 5)))
 (b ((length 5) (size 7))))

您有一个测试说明,如下所示:

(and (> length 4) (< size 8))

现在你想看看是否

(my-equal '(and (> length 4) (< size 8)) '((length 5) (size 7))

是真的。

所以任务是编写MY-EQUAL。通常我会把它写成递归函数。

但是如果你想用EVAL来做,那就相对容易了:

您想要评估此表单:

(let ((length 5) (size 7))
  (and (> length 4) (< size 8)))

现在写MY-EQUAL应该很容易。

您可以将其用作

(find term sequence :test #'my-equal :key #'second)

请注意,评估从流中读取的任意代码是一种安全风险。

<强>加成

我们可以使用COMPILE代替EVAL:

(defun lookup (v bindings)
  (let ((result (assoc v bindings)))
    (if result
        (second result)
      (error "variable ~a not known" v))))

(defparameter *query-operators* '(and or > < =))

(defun generate-query-code (q bindings)
  (cond ((numberp q) q)
        ((symbolp q) `(lookup ',q ,bindings))
        ((consp q)
         (destructuring-bind (op . args)
             q
           (if (member op *query-operators*)
               `(,op ,@(mapcar (lambda (arg)
                                 (generate-query-code arg bindings))
                               args))
             (error "Unknown op ~a" op))))))

(defun compile-query (q)
  (compile nil
           (let* ((bindings (gensym "bindings"))
                  (code (generate-query-code q bindings)))
             `(lambda (,bindings)
                ,code))))

(defun find-query (query descriptions)
  (find-if (compile-query query)
           descriptions
           :key #'second))

示例:

CL-USER 39 > (find-query '(and (> length 4) (< size 8))
                         '((a ((length 3) (size 5)))
                           (b ((length 5) (size 7)))))
(B ((LENGTH 5) (SIZE 7)))

答案 1 :(得分:4)

此博客文章与您的问题相关:http://xach.livejournal.com/131456.html

(您必须使用lengthsize之间的小映射以及每条记录的实际值进行扩展,以便可以在每条记录上调用闭包链。