严格和延迟的评估
在 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.