ligo/gitlab-pages/docs/language-basics/functions.md
2020-02-06 11:48:59 +01:00

208 lines
6.1 KiB
Markdown

---
id: functions
title: Functions
---
Writing code is fun as long as it does not get out of hand. To make
sure our code does not turn into spaghetti, we can structure some
logic into functions.
## Blocks
In PascaLIGO, *blocks* enable the sequential composition of
instructions into an isolated scope. Each block needs to include at
least one instruction. If we need a placeholder, we use the
instruction `skip` which leaves the state unchanged. The rationale
for `skip` instead of a truly empty block is that it prevents you from
writing an empty block by mistake.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo skip
// terse style
block { a := a + 1 }
// verbose style
begin
a := a + 1
end
```
Blocks are more versatile than simply containing instructions:
they can also include *declarations* of values, like so:
```pascaligo skip
// terse style
block { const a : int = 1 }
// verbose style
begin
const a : int = 1
end
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Defining a function
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
Functions in PascaLIGO are defined using the `function` keyword
followed by their `name`, `parameters` and `return` type definitions.
Here is how you define a basic function that computes the sum of two
integers:
```pascaligo group=a
function add (const a : int; const b : int) : int is
block {
const sum : int = a + b
} with sum
```
The function body consists of two parts:
- `block { <instructions and declarations> }` - logic of the function
- `with <value>` - the value returned by the function
#### Blockless functions
Functions that can contain all of their logic into a single expression
can be defined without a block. Instead of a block, you put an
expression, whose value is implicitly returned by the function, like
so:
```pascaligo group=b
function add (const a: int; const b : int) : int is a + b
```
You can call the function `add` defined above using the LIGO compiler
like this:
```shell
ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.ligo add '(1,2)'
# Outputs: 3
```
<!--CameLIGO-->
Functions in CameLIGO are defined using the `let` keyword, like other
values. The difference is that a succession of parameters is provided
after the value name, followed by the return type. This follows OCaml
syntax. For example:
```cameligo group=c
let add (a : int) (b : int) : int = a + b
```
You can call the function `add` defined above using the LIGO compiler
like this:
```shell
ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.mligo add '(1,2)'
# Outputs: 3
```
CameLIGO is a little different from other syntaxes when it comes to
function parameters. In OCaml, functions can only take one
parameter. To get functions with multiple arguments like we are used
to in imperative programming languages, a technique called
[currying](https://en.wikipedia.org/wiki/Currying) is used. Currying
essentially translates a function with multiple arguments into a
series of single argument functions, each returning a new function
accepting the next argument until every parameter is filled. This is
useful because it means that CameLIGO supports
[partial application](https://en.wikipedia.org/wiki/Partial_application).
Currying is however *not* the preferred way to pass function arguments
in CameLIGO. While this approach is faithful to the original OCaml,
it is costlier in Michelson than naive function execution accepting
multiple arguments. Instead, for most functions with more than one
parameter, we should gather the arguments in a
[tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as
a single parameter.
Here is how you define a basic function that accepts two `ints` and
returns an `int` as well:
```cameligo group=b
let add (a, b : int * int) : int = a + b // Uncurried
let add_curry (a : int) (b : int) : int = add (a, b) // Curried
let increment (b : int) : int = add_curry 1 // Partial application
```
You can run the `increment` function defined above using the LIGO
compiler like this:
```shell
ligo run-function gitlab-pages/docs/language-basics/src/functions/curry.mligo increment 5
# Outputs: 6
```
The function body is a single expression, whose value is returned.
<!--ReasonLIGO-->
Functions in ReasonLIGO are defined using the `let` keyword, like
other values. The difference is that a succession of parameters is
provided after the value name, followed by the return type.
Here is how you define a basic function that sums two integers:
```reasonligo group=b
let add = ((a, b): (int, int)) : int => a + b;
```
You can call the function `add` defined above using the LIGO compiler
like this:
```shell
ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.religo add '(1,2)'
# Outputs: 3
```
The function body is a single expression, whose value is returned.
<!--END_DOCUSAURUS_CODE_TABS-->
## Anonymous functions (a.k.a. lambdas)
It is possible to define functions without assigning them a name. They
are useful when you want to pass them as arguments, or assign them to
a key in a record or a map.
Here is how to define an anonymous function:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=c
function increment (const b : int) : int is
(function (const a : int) : int is a + 1) (b)
const a : int = increment (1); // a = 2
```
You can check the value of `a` defined above using the LIGO compiler
like this:
```shell
ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.ligo a
# Outputs: 2
```
<!--CameLIGO-->
```cameligo group=c
let increment (b : int) : int = (fun (a : int) -> a + 1) b
let a : int = increment 1 // a = 2
```
You can check the value of `a` defined above using the LIGO compiler
like this:
```shell
ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.mligo a
# Outputs: 2
```
<!--ReasonLIGO-->
```reasonligo group=c
let increment = (b : int) : int => ((a : int) : int => a + 1)(b);
let a : int = increment (1); // a = 2
```
You can check the value of `a` defined above using the LIGO compiler
like this:
```shell
ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.religo a
# Outputs: 2
```
<!--END_DOCUSAURUS_CODE_TABS-->