2014-10-20 83 views
1

在運行時需要引用符號(在R7RS中很小,如果很重要),是否存在Scheme中的任何情況?我正在研究編寫一個編譯器,並且如果運行時符號解引用不是必需的,那麼我會在編譯時執行它,因爲這更容易,可能效率更高。Scheme運行時符號解引用

舉個例子:

(define (fac n) 
    (if (> n 1) 
    (* n (f (- n 1))) 
    1)) 

; When I compile this, I know from the last line what fac is and can compile this as a direct call to my compiled function, fac. 
(fac 5) 

回答

2

考慮一下:

(define (fac n) 
    (if (> n 1) 
    (* n (fac (- n 1))) 
    1)) 

(fac 5) ;-> 120 

(define fac2 fac) 
(set! fac (lambda a 10)) 

(fac2 5) ;-> 50 

所有變量是可變的,並參考函數體內的名字fac繼續查找從定義全局範圍,這意味着如果函數包含對全局變量的引用,則該函數的行爲可以隨時更改,即使它的主體代碼沒有任何變化。

如果您希望能夠將事情優化到直接調用靜態目標,您需要確保它們只在已知的封閉範圍內進行搜索(不導出任何可能自己修改該變量的過程) 。例如: -

(define fac 
    (letrec ((fac (lambda (n)  
        (if (> n 1) (* n (fac (- n 1))) 1)))) 
     fac)) 

(fac 5) ;-> 120 
(define fac2 fac) 
(set! fac (lambda a 10))         
(fac2 5) ;-> 120 

fac這一定義機體受到letrec成立範圍,您可以靜態地證明絕不會被修改,因此內搜索可以被編譯成一個簡單的靜態調用。

您可以在多個函數中定義多個函數,具體取決於來自全局頂層的其他名稱以及其他名稱。同樣的let塊,以提供一個封閉的上下文,讓他們在內部使用更高效的查找。 Chez Scheme documentation explicitly recommends doing this使其優化器的生活更輕鬆。

+0

這可能不是問題,他打算像斯大林一樣編譯(處女方案,加載,執行,退出) – Sylwester 2014-10-20 20:28:25

+0

我花了一段時間纔看到問題。它*是一個問題。所以運行時符號管理是必要的?在這一點上,編譯幾乎是毫無意義的,如果每個變量的引用都必須通過一個運行時庫,那麼對編譯進行解釋是否有任何好處? – Tyler 2014-10-21 03:44:36

+1

@泰勒*變量*管理是必要的...你可能想澄清在q。正是你所說的「符號」管理的意思(Scheme沒有像一些Lisp那樣的動態符號查找)。以上隻影響頂級和其他環境中的變量,而編譯器無法證明它們永遠不會被修改 - 您可以在本地範圍或模塊中永久捕獲的任何內容都可爲優化提供充足的機會。正確捕獲算術運算符通常可以讓一個好的編譯器產生非常快的代碼。 – Leushenko 2014-10-21 04:47:30

相關問題