儘管可能沒有辦法完成您想要做的事情,但有一些方法可以將相似的東西拼湊在一起。一種選擇是定義一個新的綁定表單,可調用,允許我們將函數本地綁定到可調用對象。例如,我們可以讓
(with-callable ((x (make-array ...)))
(x ...))
大致相當於
(let ((x (make-array ...)))
(aref x ...))
這裏是一個可能的定義與可調用:
(defmacro with-callable (bindings &body body)
"For each binding that contains a name and an expression, bind the
name to a local function which will be a callable form of the
value of the expression."
(let ((gensyms (loop for b in bindings collect (gensym))))
`(let ,(loop for (var val) in bindings
for g in gensyms
collect `(,g (make-callable ,val)))
(flet ,(loop for (var val) in bindings
for g in gensyms
collect `(,var (&rest args) (apply ,g args)))
,@body))))
所有剩下的就是定義做出不同的方法 - 可用於訪問對象的返回閉包。例如,下面是將其定義爲數組的方法:
(defmethod make-callable ((obj array))
"Make an array callable."
(lambda (&rest indices)
(apply #'aref obj indices)))
由於這句法是一種醜陋的,我們可以使用宏,使其更漂亮。
(defmacro defcallable (type args &body body)
"Define how a callable form of TYPE should get access into it."
`(defmethod make-callable ((,(car args) ,type))
,(format nil "Make a ~A callable." type)
(lambda ,(cdr args) ,@body)))
我們做陣列可調用,我們可以使用:
(defcallable array (obj &rest indicies)
(apply #'aref obj indicies))
好多了。我們現在有一個可調用的表單,它將定義允許我們訪問對象的本地函數,以及一個可僞造的宏,它允許我們定義如何製作其他類型的可調用版本。這種策略的一個缺陷是我們每次想要使對象可調用時都必須明確地使用with-callable。
另一種選擇,類似於可調用的對象是弧形的結構訪問ssyntax。基本上x.5訪問x中索引爲5的元素。我能夠在Common Lisp中實現這一點。你可以看到我爲它編寫的代碼here和here。我也有測試,所以你可以看到使用它看起來像here。
我的實現是如何工作的我寫了一個宏w/ssyntax,它查看了正文中的所有符號,併爲其中的一些符號定義了宏和符號宏。例如,x.5的符號宏可以是(get x 5),其中get是我定義的訪問結構的通用函數。這個缺點是我總是不得不在任何我想使用ssyntax的地方使用w/ssyntax。幸運的是,我能夠將其隱藏在像defun一樣行動的宏指令中。
實際上,在Clojure中這超出了命名空間的分離。下面的Clojure可以像你期望的那樣工作:'({:a「第一個鍵」:b「第二個鍵」}:a)'會產生第一個鍵「,所以Clojure在這個行爲就像* Lisp Machine Lisp *尊重。所以,是的,在Clojure中,對於某些類型的「數據在函數名稱空間中」。 「我們想要那個嗎?」顯然,korrok對此的回答是肯定的,但Common Lisps的答案是非常不。 JFTR雖然採用Clojure的方式實現了一些非常簡潔的解決方案,但它們有時很難掌握。 – schaueho
@schauerho:問題是,鑑於其語義,我們是否需要Common Lisp? CL是Lisp-2,Clojure是Lisp-1。 –
我也希望字面數據作爲函數在調用中沒有用處,因爲它比較少見。使用綁定數據作爲函數似乎是一個不太少見的用例... –