Прежде всего, может быть полезно отметить, что ни одна из вещей, которые вы определили, не является функцией - eagerFunc
и theValue
являются значениями типа int
, а lazyFunc
- значениями типа Lazy<int>
. Учитывая
let lazyTwo = lazy (1 + 1)
и
let eagerTwo = 1 + 1
выражение 1 + 1
будет не оцениваться более одного раза, независимо от того, сколько раз вы используете eagerTwo
. Разница в том, что 1 + 1
будет оцениваться точно один раз, когда определяет eagerTwo
, но будет оцениваться не более один раз, когда lazyTwo
равно used (он будет оцениваться при первом обращении к свойству Value
, а затем кэшироваться, так что при дальнейшем использовании Value
его не нужно будет пересчитывать). Если lazyTwo
Value
никогда не доступен, то его тело 1 + 1
не будет никогда не будет оценено.
Как правило, вы не увидите большой пользы от использования ленивых значений в строгом языке, таком как F #. Они добавляют небольшие накладные расходы, так как доступ к свойству Value
требует проверки того, было ли это значение уже рассчитано. Они могут сэкономить вам немного вычислений, если у вас есть что-то вроде let lazyValue = lazy someVeryExpensiveCalculationThatMightNotBeNeeded()
, поскольку дорогостоящий расчет будет иметь место, только если значение действительно используется. Они также могут заставить некоторые алгоритмы завершаться, что иначе не произойдет, но это не главная проблема в F #. Например:
// throws an exception if x = 0.0
let eagerDivision x =
let oneOverX = 1.0 / x
if x = 0.0 then
printfn "Tried to divide by zero" // too late, this line is never reached
else
printfn "One over x is: %f" oneOverX
// succeeds even if x = 0.0, since the quotient is lazily evaluated
let lazyDivision x =
let oneOverX = lazy (1.0 / x)
if x = 0.0 then
printfn "Tried to divide by zero"
else
printfn "One over x is: %f" oneOverX.Value