严格和延迟的评估

在 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.