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.
!longText
To 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.
delayed6 = '(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.
delayed6 = do Nat.increment 5