208 lines
6.1 KiB
Markdown
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-->
|