2013-07-28 64 views
0

我試圖在elisp中創建一個返回另一個函數的函數。我看了一個類似問題的答案(how to return function in elisp),但不明白答案(我現在剛剛開始學習elisp,所以請原諒我的無知)。我認爲一個簡單的例子會有所幫助。首先,考慮到測試數是否整除5的功能:獲取elisp返回函數作爲返回值

(defun divisible-by-5 (x) 
    ;; tests whether a number is divsible by 5. 
    (setq remainder (% x 5)) 
    (if (= remainder 0) 1 0) 
) 

這工作得很好:

(divisible-by-5 25) 
1 

現在假設我想創建一個可以創造更多這類測試的函數功能---類似:

(defun divisible-by-z (z) 
    (lambda (z) 
    (setq remainder (% x z)) 
    (if (= remainder 0) 1 0)) 
) 

這並不工作。例如,

(defun divisible-by-3 (divisible-by-z 3)) 
(divisible-by-3 4) 

返回一個錯誤。我認爲即使看到一個人們如何實施這種模式的典型例子也會有所幫助。

回答

3

首先,確保你已經啓用lexical-binding。最簡單的方法是在當前緩衝區中評估(setq lexical-binding t)。有關該主題的更多信息可以在here找到。

你的divisible-by-z定義是不同的,你有一個輸入錯誤基本上是正確的(命名這兩個參數z;拉姆達的參數應該是x)。另外,將remainderlet - setq的綁定引入通常會保留用於變換已存在的綁定。這裏的結果:

(defun divisible-by-z (z) 
    (lambda (x) 
    (let ((remainder (% x z))) 
     (if (= remainder 0) 1 0)))) 

不能使用defun在挺你已經嘗試過的方式來創建divisible-by-3 - 該公司預計參數列表中一個新的功能是,你必須調用divisible-by-z

你既可以創建一個全球性的,動態的,

(defvar divisible-by-3 (divisible-by-z 3)) 

或本地,詞彙的結合結合與

(let ((divisible-by-3 (divisible-by-z 3))) 
    ...) 

無論哪種方式,你那麼就需要使用funcall調用的函數

(funcall divisible-by-3 9) ; => 1 

當然,你也可以跳過給它自己的名字enti依靠並簡單地

(funcall (divisible-by-z 3) 10) ; => 0 

funcall是必要的,因爲的Emacs Lisp是(基本上)一個Lisp-2,這意味着它可以附加既一個函數和一個值,以給定的符號。所以,當你將函數當作值(從函數返回一個函數或將函數作爲參數傳遞給函數)時,你必須告訴它看起來像是「單元」值,而不是通常的函數單元格。如果你搜索「Lisp-1 vs Lisp-2」,你會發現比你想知道的更多。

3

一個可能的解決方案:

(defun divisible-by-3 (x) 
    (funcall (divisible-by-z 3) x))