これには 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)))