Functions are also terms in Unison, so they're governed by the same conventions. A type signature is followed by a corresponding function implementation like this:
addOneis a function by the right arrow
->.When we see the arrow in a type signature, we might read the left side in human language as "takes in a" and the right side of the arrow as "returns a", as in, "addOne is a function which takes in a Nat and returns a Nat."
Great! But what if we need more than one argument to our function.
addNumsis a function which adds two numbers together to get a total.
In Unison type signatures, your function arguments are indicated to the left of each arrow
->,and the return type of the signature is the last type on the right of the arrow.
Function arguments are separated byspacesso calling a two argument function in Unison looks like:
addNums 4 5⧨9
When calling a multi-argument function, we can draw the implied parentheses for the order in which the function arguments are applied like this:
add3 : Nat -> Nat -> Nat -> Nat add3 a b c = a + b + c ((add3 1) 2) 3
Function applicationstarts with the leftmost argument--you can think of it as each argument being fed to successive functions from left to right. This might seem obvious, but later when signatures and their implementations get more complicated, an intuition for this becomes more important. You can always use parentheses to regroup expressions as needed.
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
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 samelexical scope.The exact same code with a
letblock 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.
Check out the fulllanguage reference for block syntaxfor more details.
Lambdas, or anonymous functions are unnamed functions which are defined without going through the entire term declaration process. They're typically used when the function doesn't need to be reused elsewhere in the program or when the function itself is very simple. They're often found as the arguments tohigher order functions.
While we could define the function below as a separate term to pass intoList.map,it's much simpler to define in-line.
elem -> elem Nat.+ 1is the lambda. Anything to the left of the arrow represents the parameters to the function and the expression to the right is the function body.
A lambda with two arguments is represented by separating the function arguments with spaces.
You can also choose to ignore the argument to the lambda altogether with the underscore symbol, as in the following function:
a = [1, 2, 3, 4, 5] List.map (_ -> 10) a⧨[10, 10, 10, 10, 10]
Currying means that functions with multiple arguments are expressed as a series of functions which each accept one argument. So
addNumsis a function which takes in a number and returns afunction,which takes in another number.
Function application refers to the way in which a language evaluates a function and its arguments when it is called.
For a function
ftaking an argument
x,it's common to say "we apply
See the language reference section onfunction applicationfor Unison specifics.
When we talk about lexical scope, we're referring to the context where a term can be accessed.
Terms in inner levels of nested indentations or 'let' blocks can make use of terms in outer levels, but not vice-versa.