在計算機科學中，求值策略是確定程式語言中表達式的求值的一組（通常確定性的）規則。重點典型的位於函式或運算元上 求值策略定義何時和以何種次序求值給函式的實際引數，什麼時候把它們代換入函式，和代換以何種形式發生。經常使用用來研究函式的形式系統 λ 演算來建模求值策略，這裡它們通常叫做歸約策略。求值策略分為兩大基本類，嚴格的和非嚴格的，基於如何處理給函式的實際引數。一個語言可以組合多種求值策略；例如 C 組合了傳值呼叫和傳引用呼叫。多數語言對布林表示式和 if 語句使用某種形式的非嚴格求值。 嚴格求值 在 嚴格求值中，給函式的實際引數總是在應用這個函式之前求值。 在邱奇編碼下，運算元的熱情求值對映到了函式的嚴格求值；為此嚴格求值有時叫做 熱情求值。多數現存程式語言對函式使用嚴格求值。 應用次序 應用次序（或 最左最內）求值稱呼函式的實際引數按可歸約表示式的後序遍歷從左至右的求值的策略。不像傳值呼叫，應用次序求值儘可能的在應用函式之前歸約函式體內的項。 傳值呼叫 傳值呼叫求值是最常見的求值策略，C 和 Scheme 這樣差異巨大的語言都在使用。在傳值呼叫中實際引數被求值，其值被繫結到函式中對應的變數上（通常是把值複製到新記憶體區域）。如果函式或過程能把值賦給它的形式引數，則被賦值的只是區域性複製 就是說，在函式返回後呼叫者作用域裡的曾傳給函式的任何東西都不會變。 傳值呼叫不是一個單一的求值策略，而是指一類函式的實參在被傳給函式之前就被求值的求值策略。儘管很多使用傳值呼叫的程式語言（如、、）從左至右的求值函式的實際引數，某些語言（比如 OCaml）從右至左的求值函式和它們的實際引數，而另一些語言（比如和 C）未指定這種次序（儘管它們保證）。 傳引用呼叫 在 傳引用呼叫求值中，傳遞給函式的是它的實際引數的隱式引用而不是實參的複製。通常函式能夠修改這些引數（比如賦值），而且改變對於呼叫者是可見的。因此傳引用呼叫提供了一種呼叫者和函式交換資料的方法。傳引用呼叫的語言中追蹤函式呼叫的副作用比較難，易產生不易察覺的。 很多語言支援某種形式的傳引用呼叫，但是很少有語言預設使用它。FORTRAN II 是一種早期的傳引用呼叫語言。一些語言如 C、PHP、Visual Basic NET、C 和 REALbasic 預設使用傳值呼叫，但是提供一種傳引用的特別語法。 在那些使用傳值呼叫又不支援傳引用呼叫的語言裡，可以用引用（引用其他物件的物件），比如指標（表示其他物件的記憶體地址的物件）來模擬。C 和 ML 就用了這種方法。這不是一種不同的求值策略（語言本身還是傳值呼叫）。它有時被叫做 傳地址呼叫。這可能讓人不易理解。在 C 之類不安全的語言裡會引發解引用空指標之類的錯誤。但的引用是型別安全和記憶體安全的。 類似的效果可由傳共享物件呼叫（傳遞一個可變物件）實現。比如、。 例：C 用指標模擬的傳引用呼叫 void modify int p int q int r p 27 passed by value only the local parameter is modified q 27 passed by value or reference check call site to determine which r 27 passed by value or reference check call site to determine which int main int a 1 int b 1 int x 1 int c x modify a b c a is passed by value b is passed by reference by creating a pointer c is a pointer passed by value b and x are changed return 0 傳共享物件呼叫 傳共享物件呼叫的方式由命名，並被、（物件型別）、、、等語言使用。 與傳引用呼叫不同，對於呼叫者而言在被呼叫函數里修改引數是沒有影響的。如果要達成傳引用呼叫的效果就需要傳一個共享物件，一旦被呼叫者修改了物件，呼叫者就可以看到變化（因為物件是共享的，沒有複製）。比如這段程式碼： def f l lappend 1 l 2 m f m print m 會輸出 1 而不是 2。因為列表是可變的，方法改變了 m。而賦值區域性變數 l 的行為對外面作用域沒有影響（在這類語言中賦值是給變數繫結一個新物件，而不是改變物件）。 使用 CC 語言的程式設計師可能因不能用指標等使函式返回多個值而感到不便，但是像這樣的語言提供了替代方案：函式能方便的返回多個值，比 C11 的 stdtie 更加簡單。 傳復件 恢復呼叫 傳復件 恢復呼叫、傳值 結果呼叫 或 傳值 返回呼叫（在 Fortran 社群中的術語）是傳引用呼叫的特殊情況，即在傳引用呼叫時，向被叫程序所傳遞的引用並非呼叫程序原有的引用，而是一個原有引用的複製，即被傳遞的引用與呼叫程序沒有關係。傳復件 恢復呼叫在這種情況下很重要：如果函式呼叫的一個形式引數，是可能被其他執行執行緒同時訪問的引用。那麼就把這個引用的內容複製到一個新建立的引用中，再將這個新建立的、與呼叫程序無關的引用傳遞給被叫程序。當被叫程序執行結束、呼叫返回的時候，再把這個新引用中更新過的內容複製回呼叫程序原來的引用中（恢復）。 傳值 返回呼叫的語義在兩個或更多實際引數相互是別名的時候也不同於傳引用呼叫，就是說它們都指向了在呼叫者環境中的同一個變數。在傳引用呼叫下，寫其中一個會影響另一個；傳值 返回呼叫透過給函式以獨自的復件來避免了這種情況，但沒有規定在呼叫者環境中的結果 依賴於哪個別名實際引數首先被複制回去。 當引用未初始化就傳遞給被呼叫者的時候，這種求值策略可以叫 傳結果呼叫。 部分求值 在 部分求值中，求值可以延續到仍未被應用的函式體之內。求值不包含未繫結變數的任何子表示式，並且歸約其實際引數值是已知的函式應用。在有副作用存在的時候，完全部分求值可能產生未預期的結果，支援部分求值的系統趨向只把它用於函式內 純 表示式 沒有副作用的表示式。 非嚴格求值 在 非嚴格求值中，不求值給函式的實際引數，除非它們在函式體內實際上被用到了。 在邱奇編碼下，運算元的惰性求值對映到了函式的非嚴格求值；為此，非嚴格求值有時也叫做 惰性求值。布林表示式在很多語言中使用惰性求值；在這種上下文中它通常叫做短路求值。條件表示式也通常使用惰性求值，但出於不同的原因。 正常次序 正常次序（或 最左最外）求值是總是歸約的最外可歸約式，在求值函式的實際引數之前應用函式的求值策略。它不同於傳名呼叫，傳名呼叫不進入未應用的函式體內求值。 傳名呼叫 在 傳名呼叫求值中，根本就不求值給函式的實際引數 而是使用避免捕獲代換把函式的實際引數直接代換入函式體內。如果實際引數在函式的求值中未被用到，則它永不被求值；如果這個實際引數使用多次，則它每次都被重新求值。（參見 Jensen 裝置。） 傳名呼叫求值超過傳值呼叫求值的優點是傳名呼叫求值在一個值存在的時候總是生成這個值，而傳名呼叫可能不終止如果這個函式的實際引數是求值這個函式所不需要的不終止計算。反過來說，在函式的實際引數會用到的時候傳名呼叫就非常慢了，這是因為實踐中幾乎總是要使用如 thunk 這樣的機制。 傳名呼叫求值很少直接實現，但是經常用於程式和程式語言的理論性質的思考中。帶有傳名呼叫語義的現實世界中的語言趨向使用傳需求呼叫求值。傳名呼叫是 ALGOL 60 中的預設求值。 傳需求呼叫 傳需求呼叫是傳名呼叫的記憶化版本，如果 函式的實際引數被求值了，這個值被儲存起來已備後續使用。在 純無副作用 設定下，這產生同傳名呼叫一樣的結果；當函式實際引數被使用兩次或更多次的時候，傳需求呼叫總是更快。 因為表示式的求值可能出現在計算內任意遠的地方，使用傳需求呼叫的語言一般不支援計算效果（比如 mutation）除非透過使用單子。這消除了其值變更先於它們的延遲求值的變數的任何未預期行為。 Haskell 是最周知的使用傳需求呼叫求值的語言。 傳宏展開呼叫 傳宏展開呼叫類似於傳名呼叫，但是使用了文字代換而不是避免捕獲代換。如果不小心的使用，宏代換可能導致變數捕獲並導致不希望的行為。衛生宏透過檢查並替換不是形式引數的陰影變數避免了這個問題。 非確定性策略 非確定性策略包括： 完全 β 歸約 在 完全 β 歸約下，任何函式應用都可以在任何時候歸約（是避免捕獲代換把函式的實際引數代換如函式內）。這甚至可以在未應用的函式體內進行。 傳預期呼叫 傳預期呼叫（或 並行傳名呼叫）類似於傳名呼叫，除了這個函式的實際引數的求值可能並行於函式體的求值（而非只在用到的時候）。兩個執行執行緒在函式體的求值中需要這個實際引數的時候同步；如果這個實際引數永不用到，實際引數的執行緒可以殺死。 最優求值 最優求值是傳需求呼叫的另一個變體，在其中函式的實際引數部分的求值一段時間（這可在執行時間調整），此後求值退出使用傳需求呼叫應用函式。這種方式避免了傳需求呼叫的某些執行時間代價，而仍保持了想要的終止特徵。 參見 Beta 正規化 Lambda 演算 引數 程式設計 引用 外部連結 Harold Abelson and Gerald Jay Sussman Structure and Interpretation of Computer Programs Second Edition MIT Press 1996 ISBN 0262011530 Henry G Baker Jr The Incremental Garbage Collection of Processes with Carl Hewitt ACM Sigplan Notices 12 August 8 1977 Pages 5559 Clem BakerFinch Clem David King Jon Hall and Phil Trinder An Operational Semantics for Parallel CallbyNeed Research report 991 Faculty of Mathematics Computing The Open University 1999 Robert Ennals and Simon Peyton Jones Optimistic Evaluation a fast evaluation strategy for nonstrict programs in ICFP03 ACM Press 2003 Jocelyn Frechot Partial Evaluation documentation for the Compose project Online Sept 25 2003 Bertram Ludäscher CSE 130 lecture notes January 24 2001 Benjamin C Pierce Types and Programming Languages MIT Press 2002 ISBN 0262162091 P Sestoft Demonstrating Lambda Calculus Reduction in T Mogensen D Schmidt I H Sudburough editors The Essence of Computation Complexity Analysis Transformation Essays Dedicated to Neil D Jones Lecture Notes in Computer Science 2566 SpringerVerlag 2002 Pages 420435 ISBN 3540003266 Category 程式語言概念