2014-12-19 85 views
2

我想添加一些元數據到一類匿名函數,以便於識別。到目前爲止,我的所有想法都是駭人聽聞或令人懷疑的:使匿名函數容易區分

一個plist項目可以工作,但顯然它只適用於符號,而不是lambda表達式。

我可以在文檔字符串中插入了一句:

(lambda (x) "is-special" ... 

但似乎真難看,或者:

(lambda (x) 
    (if 
    (eq x 'special) 
    t 
    ... 

甚至醜陋。

在函數對象上設置屬性有沒有那麼糟糕的方法?

我還可以使用的類型系統來區分我的功能:

在結構放置功能或CLOS對象是可能的,但感覺繁瑣。

是否可以創建作爲函數類型的自定義子類型的lambdas?

CLOS對象可以作爲可執行函數嗎?我正在考慮類似python的調用屬性。

+1

關於你最後的問題,在一個具有MOP(元對象協議)的實現上,你可以使用['funcallable-standard-class'](http://www.alu.org/mop/dictionary.html )並專門爲您的目的['print-object'](http://www.lispworks.com/documentation/HyperSpec/Body/f_pr_obj.htm)。 – acelent 2014-12-22 02:44:07

回答

1

編輯:快速和骯髒的選項,如果您的實現打印的fletlabels函數的名稱:

(defmacro nlambda (name (&rest lambda-list) &body body) 
    `(labels ((,name (,@lambda-list) 
       ,@body)) 
    #',name)) 

請繼續閱讀,如果您需要可靠的打印功能名稱。跟隨你的最後一個問題,假設你的Common Lisp實現


一個例子如下元對象協議(MOP):

(defclass funcallable-object() 
    ((name :initarg :name :initform nil :accessor funcallable-name) 
    (function :initarg :function :initform nil :accessor funcallable-function) 
    (:metaclass mop:funcallable-standard-class)) 

(defmethod initialize-instance :after ((object funcallable-object) &key function &allow-other-keys) 
    (setf (funcallable-function object) function)) 

(demethod (setf funcallable-function) :after (function (object funcallable-object)) 
    (mop:set-funcallable-instance-function object (or function #.(constantly nil)))) 

(defmethod print-object ((object funcallable-object) stream) 
    (print-unreadable-object (object stream :type t :identity t) 
    (with-slots (name) object 
     (when name 
     (write name stream))))) 

請注意,你必須根據你的實現替換mop包的名稱,或如果你使用cl-mop。


編輯:這裏有幾種方法可以使用它。

直接:

(make-instance 'funcallable-object 
    :name 'foo 
    :function #'(lambda (<args>) 
       <body>)) 

了宏:

(defmacro nlambda (name (&rest lambda-list) &body body) 
    `(labels ((,name (,@lambda-list) 
       ,@body)) 
    (make-instance 'funcallable-object 
     :name ',name 
     :function #',name))) 

(nlambda foo (<args>) 
    <body>) 

我用的例子,而不是fletlabels,因爲我相信一個名爲拉姆達的更大的效用是其遞歸的能力。

3

我不知道MOP還沒有回答你最後的問題,但我可以建議你採取一種駭人的方式去做你想做的事。

您可以聲明一個特殊變量來跟蹤已添加元數據的lambda表達式:(defvar *annotated-lambdas* (make-hash-table))

然後定義一個函數來從中獲取/設置lambda。

(defun get-lambda (lambda &optional (annotated-lambdas *annotated-lambdas*)) 
    (gethash lambda annotated-lambdas)) 

(defun (setf get-lambda) (annotation lambda &optional (annotated-lambdas *annotated-lambdas*)) 
    (setf (gethash lambda annotated-lambdas) annotation)) 

現在你已經可以測試的東西:

(let ((l (lambda (x) (1+ x)))) 
    (setf (get-lambda l) "Add one.")) 

此時*annotated-lambdas*它應該已經有一個元素。

現在你可以使用一個小宏,使這個不太麻煩:

(defmacro lambda* ((&rest args) (annotation &optional (annotated-lambdas *annotated-lambdas*)) &body body) 
    (let ((name (gensym))) 
`(let ((,name (lambda (,@args) 
     ,@body))) 
    (setf (get-lambda ,name ,annotated-lambdas) ,annotation)))) 

您可以使用這樣的:

(lambda* (x) ("Add one.") 
    (+1 x)) 

當然,有機會獲得註釋,你需要有權訪問lambda,我假設你這樣做,否則你會使用一個函數(它只是一個指向lambda的符號)。 此外,「註解」可以是任何東西,一個字符串,一個列表,一個alist,一個plist或者一個散列表。

+2

對。通常爲此使用非標準的弱哈希表。這樣,未參考的功能可以得到GCed ... – 2014-12-19 10:29:33

+0

@RainerJoswig你能否詳細說明一下,這聽起來很有趣。 – fstamour 2014-12-20 00:06:23

+0

@Sharpie,實現對弱哈希表的實現具有非標準支持(例如[ABCL](http://abcl.org/trac/browser/trunk/abcl/src/org/armedbear/lisp/make-hash-table)。 lisp),[Allegro CL](http://franz.com/support/documentation/9.0/doc/implementation.htm#cl-make-hash-table-2),[CLisp](http://clisp.sourceforge .net/impnotes/weak.html#weak-ht),[Clozure CL](http://ccl.clozure.com/docs/ccl.html#weak-references),[LispWorks](http:// www。 lispworks.com/documentation/lw61/LW/html/lw-654.htm#pgfId-1039790)和[SBCL](http://www.sbcl.org/manual/index.html#Hash-Table-Extensions))允許條目被GC。 – acelent 2014-12-22 11:18:12

3

如果是用於打印,我只想做:

CL-USER 8 > (flet ((foo (a b) (+ a b))) #'foo) 
#<interpreted function FOO 40600008E4> 

CL-USER 9 > (defmacro nlambda (name &rest rest) 
       `(flet ((,name ,@rest)) 
       (function ,name))) 
NLAMBDA 

CL-USER 10 > (mapcar (lambda (x) (nlambda foo (y) (+ x y))) '(1 2 3 4)) 
(#<interpreted function FOO 4060000B54> 
#<interpreted function FOO 4060000B84> 
#<interpreted function FOO 4060000BB4> 
#<interpreted function FOO 4060000BE4>) 

如果你想獲得的名字後面,你可以使用FUNCTION-LAMBDA-EXPRESSION,如果你的執行和編譯器設置允許它。我在這裏使用LispWorks。第三個值是名稱:

CL-USER 30 > (flet ((foo (a b) (+ a b))) #'foo) 
#<interpreted function FOO 406000183C> 

CL-USER 31 > (nth-value 2 (function-lambda-expression *)) 
FOO 

有關其他方法,請參閱:pretty function

+0

有沒有辦法以編程方式獲得該名稱?這將很好地工作。這不是打印。 – BnMcGn 2014-12-19 14:49:19

+0

@BnMcGn:看我編輯... – 2014-12-19 15:48:20