Delayed computations

Values in Unison are not, by default, lazily evaluated. But it's common to want to express that a value or calculation should be delayed until it's absolutely needed.

For example the termlongTextin 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 evaluatelongText--thereare circumstances where the calculation of a value might be very expensive or could introduce surprising behavior if runeagerly.

One way you might solve for this is to create a "thunk": a function with no arguments which returns the desired value or computation 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 function with the form() -> a.

We can rewrite the type() -> Textas just'Text.

longText : 'Text
longText = do "๐Ÿต Imagine infinite monkeys on infinite typewriters ๐Ÿ™Šโ€ฆ"

Just as Unison provides syntax for representing delayed computations in a type signature, there are a few ways to delay an expression in Unison.

๐Ÿง 

These are all valid ways to implement a function for the type'Text:

  • myFunction = '"delayed with single quote"
  • myFunction _ = "delayed with underscore argument"
  • myFunction = do "delayed with do keyword"

All three are equivalent in meaning.

When we want to run the thunk, we could call the value with()to represent "I'm calling this with zero arguments", but Unison also provides syntactic sugar for "forcing" or calling a thunk with the!symbol.

Calling our functionlongTextlooks like:

coinflip : Boolean -> Text
coinflip bool = if bool then !longText else "Hi"

To review: single quote,',an underscore_,or thedokeyword introduce athunkand the bang symbol,!,executes it, but what if we want to callcoinflipwith an argumenttrueand then return the result of that function application in a thunk? Our final desired return type is'Text.To do that, we have to surround the function application forcoinflip truein parentheses before prepending the single quote symbol.

delayedText : 'Text delayedText = do coinflip true !delayedText
โงจ
"๐Ÿต Imagine infinite monkeys on infinite typewriters ๐Ÿ™Šโ€ฆ"
๐Ÿง 
It might be tempting to write('coinflip true)with no parentheses in an attempt to get a return type of'Textor() -> Text,but the single quote ordosyntax delays thefunctionin that circumstance, not the result of evaluating the function.('coinflip true)has the signature(() -> Boolean) -> Textand we're trying to pass it an argument oftrue.๐Ÿ™…๐Ÿปโ€โ™€๏ธ That may not be what we're looking for. When we want to delay the result ofexecuting a function,we must surround the entire expression in parentheses.