Common Lisp 中的 Eval

All*_*ang 3 lisp functional-programming eval common-lisp


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

((a ((length 3) (size 5))) (b ((length 5) (size 7))))...
Run Code Online (Sandbox Code Playgroud)

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

(find (and (gt length 4) (lt size 8)))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,上面的函数应该适合b我。请注意,该函数的条件参数可以用andor扩展or...
我做了一些研究,知道eval可以以某种方式帮助我,但我不确定它到底是如何工作的。
有人可以给我举个例子或者给我一些提示吗?

谢谢

Rai*_*wig 5

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

您有一系列项目:

((a ((length 3) (size 5)))
 (b ((length 5) (size 7))))
Run Code Online (Sandbox Code Playgroud)

您有一个测试描述,如下所示:

(and (> length 4) (< size 8))
Run Code Online (Sandbox Code Playgroud)

现在你想看看是否

(my-equal '(and (> length 4) (< size 8)) '((length 5) (size 7))
Run Code Online (Sandbox Code Playgroud)

是真的。

所以任务就是写MY-EQUAL。通常我会将其编写为递归函数。

但如果你想用 来做到这一点EVAL,它会变得相对容易:

您想要评估此表单:

(let ((length 5) (size 7))
  (and (> length 4) (< size 8)))
Run Code Online (Sandbox Code Playgroud)

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

然后你可以使用它作为

(find term sequence :test #'my-equal :key #'second)
Run Code Online (Sandbox Code Playgroud)

请注意,对从流中读取的任意代码进行评估存在安全风险。

奖金

我们可以使用COMPILEEVAL 来代替:

(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))
Run Code Online (Sandbox Code Playgroud)

例子:

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)))
Run Code Online (Sandbox Code Playgroud)