Values in Unison are not, by default, lazily evaluated. But sometimes, you may want to delay a value or calculation until it's actually needed.
For example the term longText in the following snippet is evaluated strictly:
longText : Text
longText = "🐵 Imagine infinite monkeys on infinite typewriters 🙊…"
coinflip : Boolean -> Text
coinflip bool = if bool then longText else "Hi"But you might not actually need to evaluate longText—there are circumstances where the calculation of a value might be very expensive or could introduce surprising behavior if run eagerly.
One way you might solve for this is to create a "thunk": a function with no arguments which returns the desired value when it's called.
longText : () -> Text
longText _ = "🐵 Imagine infinite monkeys on infinite typewriters 🙊…"Because this is a common pattern, Unison provides the single quote, ', as syntactic sugar for representing a signature with the form () -> a.
We can rewrite the type () -> Text as just 'Text.
Just as Unison provides syntax for representing delayed computations in a type signature, there are a few ways to delay an expression in Unison.
When we want to run the thunk, we can call it by adding a () to the end of the function with no spaces, representing the idea: "I'm calling this function with zero arguments".
longText()⧨"🐵 Imagine infinite monkeys on infinite typewriters 🙊…"Unison also provides the ! symbol as syntactic sugar for calling a thunk. The ! is prepended to the function name.
!longTextTo review: the single quote, ', an underscore _, or the do keyword introduce a thunk and appending () or prepending ! executes it.
Caveat: Delayed computations with multiple arguments
Let's say we have a function that has one argument and returns a delayed value of Text.
coinflip : Boolean -> 'Text
coinflip bool = do if bool then longText() else "Hi"We want to call coinflip with its argument and force the thunk to get a value.
We can always write the function call with () to force the thunk:
coinflip true ()But the ! syntax applies to the the value to its immediate right, so we have to surround the function application for coinflip true in parentheses before prepending the ! symbol.
!(coinflip true)The single quote syntax for delaying a computation has the same gotcha as the ! syntax. You might think you're delaying the result of a function call with 'Nat.increment 5 but you're actually delaying the function, not result of calling it.
You'll need parenthesis around the entire expression to delay the result of a function call with the single quote syntax.
delayed = '(Nat.increment 5)The do keyword delays the result of everything to its right, so you don't need to wrap the entire expression in parentheses.
delayed = do Nat.increment 5