2016-12-05 75 views
3

我偶然發現瞭解釋Y Combinator的文章this。代碼在Scheme中,但我試圖用Common Lisp來解決它。在Common Lisp變量中定義和使用函數

但是,我無法從Scheme轉換到Common Lisp。 Scheme爲函數和(其他)變量使用單個名稱空間,但Common Lisp爲函數和變量使用不同的名稱空間。我該如何解決這種差異,才能使用Common Lisp代碼?

計劃代碼

以下是教程中的一些Scheme代碼。

在開始時,筆者定義階乘函數:

(define (factorial n) 
    if (= n 0) 
    1 
    (* n (factorial (- n 1))))) 

,並將其轉換成這樣:

(define factorial 
    (lambda (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1)))))) 

因爲(據筆者),這是計劃做什麼:

計劃只是在評估之前將第一個定義翻譯成第二個定義 。因此Scheme中的所有函數都是lambda 表達式。

Common Lisp的

我試圖重寫既Common Lisp中上述片段模仿從所述第一形式向第二這種轉變。但CL中沒有define,也沒有一個名稱空間。所以我試圖欺騙我。

重寫Common Lisp中第一個計劃的定義很簡單:

(defun factorial (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1))))) 

但(我)這個翻譯成第二個定義是有點棘手。我這樣翻譯它:

(setf (symbol-function 'factorial) 
    (lambda (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1)))))) 

這是一個不好的方法來做到這一點(或有更好的辦法)?它似乎工作,但編譯器給我一個樣式警告:未定義的函數:階乘。

回答

3

在某些方面,它更像是這樣的:

(setf (symbol-function 'factorial) 
     (labels ((factorial (n) 
       (if (= n 0) 
        1 
        (* n (factorial (- n 1)))))) 
     #'factorial)) 

LABELS定義本地功能factorial。在本地函數factorial的定義內部,對factorial的任何調用都是針對該函數的。然後我們從標籤表達式中返回這個函數。因此,您可以定義遞歸函數,其中遞歸調用不適用於未定義的函數。

如果你看看Common Lisp實現,你可以看到DEFUN經常擴展到非可移植的構造,如命名的lambda函數。另外DEFUN也有編譯時的副作用。

2

轉換在通用列表中沒有意義。

CL defun通常不僅僅是(setf fdefinition)

您可以通過評估(macroexpand-1 '(defun foo (a b c) (bar c a b)))來查看。

真正的問題是 - 你爲什麼要這樣做?

+0

我只是學習更好地鍵入自己的代碼,而不是隻讀它。也許在這種情況下,由於Scheme和Common Lisp之間的差異,這不是最好的想法。 – Frank

1

如果我理解正確,那麼您的問題主要涉及翻譯"Lisp-1" and a "Lisp-2"

Scheme是一個「Lisp-1」 - 它有一個函數和變量的單一命名空間。另一方面,Common Lisp是一個「Lisp-2」 - 它具有用於函數和變量的單獨命名空間。

在方案,你可以寫

(define foo (lambda (...) ...)) 

,然後調用foo,如:

(foo ...) 

我們可以準確Common Lisp中以同樣的方式定義foo爲好,但如果我們試圖致電foo使用該語法,您的程序將崩潰。這是因爲foo位於變量名稱空間中,而不是函數名稱空間。

我們可以解決此通過使用funcall調用foo

(funcall foo ...) 

這是一個簡單的介紹。 的Functions頁面提供了您可能會覺得有用的其他詳細信息。

+0

是的,不同的名稱空間方法是問題。我必須決定是否將該函數存儲在值單元格中(並用'funcall'調用它)或使用Rainer的解決方案(我想我會試試)。在OP中顯示的轉換隻是第一個長序列轉換,它將最終產生(定義幾乎因子 (lambda(f) (lambda(n) (if(= n 0) ((lambda(x)(xx)) (lambda(x)(f(xx)))))(定義Y (lambda(f) )(定義階乘(Y近因數))'。 – Frank

+0

@Frank,對。 Y組合器涉及傳遞函數作爲參數並應用該函數。所以我認爲無論你如何到達那裏,你都需要'funcall'。 –