2012-12-09 108 views
3


我是新來口齒不清,這裏是我的問題:
我有一個列表是像評估和演示Common Lisp中

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

上面的列表只是一個示例。
我想有一個函數find,可以工作就像一個數據庫查詢,例如

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

我這種情況下,上面的函數應該找到b我。請注意,該功能的條件參數可以用andor ...
擴展我做了一些研究,知道eval可以以某種方式幫助我,但我不確定它是如何工作的。
有人可以給我看一個例子,或者給我一些提示嗎?

謝謝

回答

4

本博客文章看起來與您問題相關:http://xach.livejournal.com/131456.html

( ÿ您必須用lengthsize之間的小映射以及您的每條記錄的實際值進行擴展,因此可以在每條記錄上調用封閉鏈)

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做到這一點,它會比較容易:

你想EVAL這種形式:

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

現在,應該是容易寫MY-相等。

您可以使用它那麼作爲

(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)))