2013-06-29 81 views
2

如何定義mutator elisp函數?也就是說,如何將參數發送到函數內部可以修改的elisp函數以供在函數外部使用(類似於非常量引用變量或C++中的指針)?例如,假設我有一個函數foo定義如下Mutator elisp函數

(defun foo (a b c d) 
    ;do some stuff to b, c, and d 
     . 
     . 
     . 
) 

我可能喜歡稱呼它,比如,如下

(defun bar (x) 
    (let ((a) (b) (c) (y)) 
    . 
    . 
    . 
     ;a, b and c are nil at this point 
     (foo x a b c) 
     (setq y (some-other-function-of a b c x and-other-variables)) 
    . 
    . 
    . 
)) ...) 
    y) 

我知道我可以把我的所有參數本地的一些功能到一個大的舊列表,在函數的最後評估名單,然後再從設置在該函數(的東西列表)的返回值,其他一些列表獲取這些變量,即

(setq return-list (foo read-only-x read-only-y)) 
(setq v_1 (car return-list)) 
(setq v_2 (cadr return-list)) 
      . 
      . 

但有沒有更好的方法?我迄今爲止所做的所有嘗試解決這個問題的函數的退出函數的變量與它們的傳遞方式沒有什麼不同

至於爲什麼我希望能夠做到這一點,我只是試圖重構一些大函數F這樣所有與某些可命名概念相關的表達式集合c都存在於它們自己的小模塊c_1,c_2,c_3,... c_n中,我可以從F內部調用任何需要在此過程中更新的參數。也就是說,我想F到看起來像:

(defun F (...) 
    (let ((a_1) (a_2) ...) 
    (c_1 a_1 ... a_m) 
    (c_2 a_h ... a_i) 
    . 
    . 
    . 
    (c_n a_j ... a_k) 
    . 
    . 
    . 
))...)) 
+0

因此,您首先編寫的文件格式很差(例如,那裏的大多數變量都是以'let'開頭的,並沒有給他們一個價值),然後想通過將副作用移到其他地方來讓它變得更糟,這樣他們就更難追蹤了?你最好在列表中返回新值(如你所建議的那樣)。你可以用'pcase-let'來更方便地分解'return-list',就像在'(pcase-let(('',,v_1,v_2)(foo read-only -x read-only-y)))。 )'。 – Stefan

+0

關於未賦值的讓變量沒有任何價值(儘管在真實的代碼中,考慮到機會,我將在聲明中定義它們),我對此有所瞭解,但就副作用而言,我不太確定我是否同意。使用一致的變量命名約定(即i-var爲只讀,o-var爲只寫,io-var爲讀寫等等),然後通過檢查,我知道哪些變量是我想要的以副作用。此外,無論我是通過函數返回還是通過副作用來分配值,我仍然需要充分調查函數以瞭解在任何情況下都返回的結果。 – HexedAgain

+0

無論如何,我很感激你的迴應(我正在努力提高我的這種語言技能 - 尤其是因爲這樣做立刻有利可圖),而且我不知道pcase-let – HexedAgain

回答

2

兩種方式我能想到的:

  • 使「功能」富宏,而不是一個功能(如果可能)
  • 通過新創建的利弊(或更多的人)進入功能,並通過setcar/setcdr取代他們的汽車和CDR

萬一功能太複雜了,你也可以結合這兩種方法 - 哈e是一個創建a和b的缺點並用該缺點調用函數foo0的宏foo,然後再次解包汽車和cdr。

如果您需要超過2個參數,只需使用多個參數作爲參數。

+0

感謝你,我就像cons cell的想法一樣(我需要進一步閱讀如何正確使用宏) – HexedAgain

0

只是爲了告訴你它是如何做到的,但不這樣做,這是不好的風格。

(defun set-to (in-x out-y) 
    (set out-y in-x)) 

(let (x) 
    (set-to 10 'x) 
    x) 

有當這雖然不會正常工作的情況下:

(let (in-x) 
    (set-to 10 'in-x) 
    in-x) 

這有點像這樣的C++代碼

void set_to(int x, int* y) { 
    *y = x; 
} 

int y; 
set_to(10, &y); 

其實我希望有在任何非const引用C++,因此每個mutator都必須用上面的指針調用。

再次,不要這樣做,除非它是真的需要。 改爲使用multiple-value-bindcl-flet