回答

3

好吧,有一大堆討論pro和con的網站,所以我不會去那裏。

一個有趣的語言,它具有一些與動態範圍相似的特徵是XSLT;雖然XSLT的模板和變量等在詞彙範圍上,但XSLT當然都是關於XML的 - 而且xml樹中的當前位置是「動態範圍」的,因爲上下文節點是全局的,因此XPath表達式不被評估根據XSLT的詞彙範圍,但根據其動態評估。

7

Mathematica是另一種通過Block構造動態確定範圍的語言。使用公式時,這實際上非常有用。它可以讓你寫的東西像

In[1]:= expr = a*t^2 + b*t+ c; 

In[2]:= Block[{a = 1, b = -1, c = 2}, Table[expr, {t, 5}]] 
Out[2]= {2, 4, 8, 14, 22} 

如果像at變量詞法範圍這不會在所有的工作。它對Mathematica的規則重寫系統非常有效,除此之外,如果它們沒有現有的定義,則會使變量不被評估(作爲符號表達式)。

Mathematica可以僞造Module構造的詞法作用域,但是這實際上是用新的,據稱是唯一的符號來重寫表達式(如果預測下一個獨特符號將會是什麼,那麼可能會導致衝突,這很容易在多數情況下)。這意味着

Module[{x = 4}, 
    Table[x * t, {t, 5}]] 

會變成這樣的事:

Block[{x$134 = 4}, 
    Table[x$134 * t, {t, 5}] 

的Emacs Lisp在其圖書館之一,有一個叫做lexical-let結構(一個真正的Lisp的宏)拉完全相同的伎倆僞造詞彙範圍。

由於您需要動態變量與其當前值之間的某種映射,因此在編譯您的語言時,實際詞彙範圍設置具有性能優勢,而您沒有使用ELisp或Mathematica的假詞彙,做查找(通過散列表或屬性列表或其他)和其他間接層。

編輯:如果你只有詞法變量,你可以通過存儲在進入的範圍和低保舊值在退出範圍恢復了全球性的,詞法變量的原始值假動態作用域。爲了確保這一點,你需要像Lisp的UNWIND-PROTECTfinally塊。我已經看到使用C++析構函數完成這些工作,主要是作爲練習。

9

動態範圍的語言更容易實現。要訪問不在當前活動記錄/堆棧幀中的變量,只需遵循控制鏈接。靜態/詞彙訪問鏈接不需要,使得堆棧幀變小。

動態變量在運行時可能是「不可預知的」,因爲需要知道實際棧幀的順序是要知道將使用哪個變量。通過查看代碼的靜態結構,這些信息不可用。如果程序的實際調用圖在執行時不容易預測,則很容易被人發現。這就是爲什麼今天大多數語言都有靜態範圍界定(然而,大多數異常系統是動態的,因爲這是最實用的)。

但是在某些情況下,動態範圍變量非常有用。例如,當重定向輸出時,可以使用動態變量爲本地代碼設置標準輸出,並從那裏調用所有代碼。

(let ((*standard-output* *some-other-stream*)) 
(stuff)) 

在該共口齒不清示例(從塞貝爾),標準輸出被綁定到另一個流的設形式的持續時間,(其包圍的括號內)。當執行離開的時候,它會回到之前的任何事情。請參閱http://gigamonkeys.com/book/variables.html Peter Seibels的免費優秀書籍Practical Common Lisp進行了良好的討論。在Seibels自己的話中:

動態綁定使全局變量更容易管理,但重要的是要注意他們仍然允許在遠處採取行動。綁定一個全局變量有兩個距離效果 - 它可以改變下游代碼的行爲,並且它還可能打開下游代碼將一個新值分配給堆棧上更高的綁定的可能性。只有在需要利用這些特徵中的一個或兩個時,才應使用動態變量。

3

動態範圍更容易與解釋器一起實現。大多數早期的Lisp解釋器都在使用動態範圍。幾年後,詞法範圍被發現有優勢,但最初主要是在Lisp編譯器中實現的。出現了幾種實現動態範圍的解釋代碼和編譯代碼中的詞法範圍。一些提供了一種特殊的語言結構來提供閉包。像Scheme和Common Lisp這樣的Lisp方言要求解釋和編譯代碼之間沒有區別,因此基於解釋的實現也必須實現詞法範圍。

早期的Smalltalk實現實現了動態範圍。各種Lisp方言實現實現了動態範圍(Interlisp,UCI Lisp,Lisp Machine Lisp,MacLisp,...)。

幾乎所有來自過去20年的新Lisp方言都默認使用詞法作用域,甚至是專門使用。一些出版物詳細描述瞭如何用詞法範圍實現Lisp - 所以沒有理由不使用詞法範圍。

2

所有shell語言(bash,ksh等)都使用動態作用域。

相關問題