嚴格和延遲的評估

在 elm 中,在應用最後一個引數時計算函式的值。在下面的示例中,當使用 3 個引數呼叫 f 或使用最後一個引數應用 f 的 curry 形式時,將列印 log 的診斷。

import String
import Debug exposing (log)

f a b c = String.join "," (log "Diagnostic" [a,b,c]) -- <function> : String -> String -> String -> String

f2 = f "a1" "b2" -- <function> : String -> String

f "A" "B" "C"
-- Diagnostic: ["A","B","C"]
"A,B,C" : String

f2 "c3"
-- Diagnostic: ["a1","b2","c3"]
"a1,b2,c3" : String

有時你會想要阻止一個功能立即應用。elm 中的典型用法是 Lazy.lazy ,它提供了一個抽象來控制何時應用函式。

lazy : (() -> a) -> Lazy a

延遲計算採用一個 ()Unit 型別引數的函式。單位型別通常是佔位符引數的型別。在引數列表中,相應的引數指定為 _,表示未使用該值。elm 中的單位值由特殊符號 () 指定,它可以在概念上表示空元組或空洞。它類似於 C,Javascript 和其他使用括號進行函式呼叫的語言中的空引數列表,但它是一個普通值。

在我們的例子中,可以保護 f 不被 lambda 立即評估:

doit f = f () -- <function> : (() -> a) -> a
whatToDo = \_ -> f "a" "b" "c" -- <function> : a -> String
-- f is not evaluated yet

doit whatToDo
-- Diagnostic: ["a","b","c"]
"a,b,c" : String

只要部分應用功能,功能評估就會延遲。

defer a f = \_ -> f a -- <function> : a -> (a -> b) -> c -> b

delayF = f "a" "b" |> defer "c" -- <function> : a -> String

doit delayF
-- Diagnostic: ["a","b","c"]
"a,b,c" : String

Elm 具有 always 功能,不能用於延遲評估。因為 elm 評估所有函式引數,無論是否以及何時使用函式應用程式的結果,在 always 中包裝函式應用程式都不會導致延遲,因為 f 完全作為引數應用於 always

alwaysF = always (f "a" "b" "c") -- <function> : a -> String
-- Diagnostic: ["a","b","c"] -- Evaluation wasn't delayed.