A block is a section of Unison code which is grouped together to organize smaller units of code. One of the many places you'll start a code block is after a term definition. We can introduce a code block via indentation or via a let
block.
repeatNum : Nat -> Text
repeatNum num =
text = Nat.toText num
Text.repeat num text
In the example above, we've opted to use indentation to delimit the code block. Everything at the same indentation level is within the same block and therefore shares the same lexical scope. The exact same code with a let
block looks like:
repeatNum : Nat -> Text
repeatNum num = let
text = toText num
Text.repeat num text
🪆 Blocks can be nested within other blocks, and terms in inner blocks can reference terms from their enclosing blocks.
nesting : [Text]
nesting =
parent = "outer"
inner1 = let
child1 = "child1"
inner2 = let
child2 = "child2"
[parent, child1, child2]
inner2
inner1
The last thing evaluated in a code block is the return value for that entire code block. Below we have a series of expressions whose values are ultimately discarded even though each line of the code block is actually executed.
myFunction : Text
myFunction =
use Nat +
x = 1 + 1
y = "I am unreachable!"
z = ?a
"I am what is returned."
myFunction⧨"I am what is returned."
The UCM will fail to compile a block which contains a sub-expression that is not used or bound to a variable and does not return Unit
. That means the following function will fail to typecheck and cannot be added to the codebase because both 1 Nat.+ 1
and the doc fragment are not used elsewhere in the function.
invalidFunction : Text
invalidFunction =
Debug.trace "I am ok because I return unit!" ()
1 + 1
"returned value"
Check out the full language reference for block syntax for more details.