ligo/gitlab-pages/docs/language-basics/loops.md

217 lines
5.9 KiB
Markdown
Raw Normal View History

2020-01-02 00:30:55 +04:00
---
id: loops
title: Iteration
2020-01-02 00:30:55 +04:00
---
import Syntax from '@theme/Syntax';
2020-02-05 19:28:40 +04:00
## General Iteration
2020-01-02 00:30:55 +04:00
<Syntax syntax="pascaligo">
2020-02-10 22:07:20 +04:00
General iteration in PascaLIGO takes the shape of general loops, which
should be familiar to programmers of imperative languages as "while
loops". Those loops are of the form `while <condition> <block>`. Their
associated block is repeatedly evaluated until the condition becomes
true, or never evaluated if the condition is false at the start. The
loop never terminates if the condition never becomes true. Because we
are writing smart contracts on Tezos, when the condition of a "while"
loops fails to become true, the execution will run out of gas and stop
with a failure anyway.
2020-02-05 19:28:40 +04:00
Here is how to compute the greatest common divisors of two natural
2020-02-12 01:29:12 +04:00
numbers by means of Euclid's algorithm:
2020-02-05 19:28:40 +04:00
```pascaligo group=a
2020-02-10 22:07:20 +04:00
function gcd (var x : nat; var y : nat) : nat is
block {
2020-02-12 01:29:12 +04:00
if x < y then {
const z : nat = x;
x := y; y := z
}
2020-02-10 22:07:20 +04:00
else skip;
var r : nat := 0n;
while y =/= 0n block {
r := x mod y;
x := y;
y := r
2020-02-05 19:28:40 +04:00
}
2020-02-10 22:07:20 +04:00
} with x
2020-02-05 19:28:40 +04:00
```
You can call the function `gcd` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/gcd.ligo gcd '(2n*2n*3n*11n, 2n*2n*2n*3n*3n*5n*7n)'
# Outputs: +12
2020-01-02 00:30:55 +04:00
```
</Syntax>
<Syntax syntax="cameligo">
2020-01-02 00:30:55 +04:00
2020-02-05 19:28:40 +04:00
CameLIGO is a functional language where user-defined values are
constant, therefore it makes no sense in CameLIGO to feature loops,
which we understand as syntactic constructs where the state of a
stopping condition is mutated, as with "while" loops in PascaLIGO.
Instead, CameLIGO loops are written by means of a tail recursive function
2020-02-05 19:28:40 +04:00
2020-02-10 22:07:20 +04:00
Here is how to compute the greatest common divisors of two natural
2020-02-12 01:29:12 +04:00
numbers by means of Euclid's algorithm:
2020-02-10 22:07:20 +04:00
2020-02-06 14:47:41 +04:00
```cameligo group=a
let rec iter (x,y : nat * nat) : nat =
if y = 0n then x else iter (y, x mod y)
2020-02-05 19:28:40 +04:00
let gcd (x,y : nat * nat) : nat =
let x,y = if x < y then y,x else x,y in
iter (x,y)
2020-02-05 19:28:40 +04:00
```
> Note that `fold_while`, `stop` and `continue` (now `Loop.resume`) are
2020-02-26 16:36:50 +04:00
> *deprecated*.
2020-02-05 19:28:40 +04:00
You can call the function `gcd` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/gcd.mligo gcd (2n*2n*3n*11n, 2n*2n*2n*3n*3n*5n*7n)'
# Outputs: +12
2020-01-02 00:30:55 +04:00
```
</Syntax>
<Syntax syntax="reasonligo">
2020-02-05 19:28:40 +04:00
ReasonLIGO is a functional language where user-defined values are
constant, therefore it makes no sense in ReasonLIGO to feature loops,
which we understand as syntactic constructs where the state of a
stopping condition is mutated, as with "while" loops in PascaLIGO.
Instead, ReasonLIGO loops are written by means of tail recursive functions
2020-02-05 19:28:40 +04:00
2020-02-10 22:07:20 +04:00
Here is how to compute the greatest common divisors of two natural
2020-02-12 01:29:12 +04:00
numbers by means of Euclid's algorithm:
2020-02-10 22:07:20 +04:00
2020-02-06 14:47:41 +04:00
```reasonligo group=a
let rec iter = ((x,y) : (nat, nat)) : nat =>
if (y == 0n) { x; } else { iter ((y, x mod y)); };
2020-02-06 14:47:41 +04:00
let gcd = ((x,y) : (nat, nat)) : nat => {
2020-02-05 19:28:40 +04:00
let (x,y) = if (x < y) { (y,x); } else { (x,y); };
iter ((x,y))
2020-02-06 14:47:41 +04:00
};
2020-01-03 00:26:02 +04:00
```
> Note that `fold_while`, `stop` and `continue` (now `Loop.resume`) are
2020-02-26 16:36:50 +04:00
> *deprecated*.
</Syntax>
<Syntax syntax="pascaligo">
2020-01-02 00:30:55 +04:00
2020-02-10 22:07:20 +04:00
## Bounded Loops
2020-01-02 00:30:55 +04:00
2020-02-10 22:07:20 +04:00
In addition to general loops, PascaLIGO features a specialised kind of
*loop to iterate over bounded intervals*. These loops are familiarly
2020-02-12 01:29:12 +04:00
known as "for loops" and they have the form `for <variable assignment>
to <upper bound> <block>`, as found in imperative languages.
2020-01-02 00:30:55 +04:00
2020-02-12 01:29:12 +04:00
Consider how to sum the natural numbers up to `n`:
2020-01-02 00:30:55 +04:00
2020-02-06 14:47:41 +04:00
```pascaligo group=c
2020-02-05 19:28:40 +04:00
function sum (var n : nat) : int is block {
var acc : int := 0;
for i := 1 to int (n) block {
acc := acc + i
}
2020-01-02 00:30:55 +04:00
} with acc
```
2020-02-10 22:07:20 +04:00
(Please do not use that function: there exists a closed form formula.)
2020-02-05 19:28:40 +04:00
You can call the function `sum` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/sum.ligo sum 7n
# Outputs: 28
```
2020-01-02 00:30:55 +04:00
2020-02-05 19:28:40 +04:00
PascaLIGO "for" loops can also iterate through the contents of a
collection, that is, a list, a set or a map. This is done with a loop
of the form `for <element var> in <collection type> <collection var> <block>`,
where `<collection type>` is any of the following keywords:
2020-02-05 19:28:40 +04:00
`list`, `set` or `map`.
2020-01-02 00:30:55 +04:00
2020-02-05 19:28:40 +04:00
Here is an example where the integers in a list are summed up.
2020-02-06 14:47:41 +04:00
```pascaligo group=d
2020-02-05 19:28:40 +04:00
function sum_list (var l : list (int)) : int is block {
var total : int := 0;
for i in list l block {
total := total + i
}
} with total
2020-01-02 00:30:55 +04:00
```
2020-02-05 19:28:40 +04:00
You can call the function `sum_list` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_list
'list [1;2;3]'
# Outputs: 6
```
Here is an example where the integers in a set are summed up.
2020-02-12 01:29:12 +04:00
```pascaligo group=d
2020-02-05 19:28:40 +04:00
function sum_set (var s : set (int)) : int is block {
var total : int := 0;
for i in set s block {
total := total + i
}
} with total
```
You can call the function `sum_set` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_set
'set [1;2;3]'
# Outputs: 6
```
Loops over maps are actually loops over the bindings of the map, that
is, a pair key-value noted `key -> value` (or any other
2020-02-12 01:29:12 +04:00
variables). Given a map from strings to integers, here is how to sum
2020-02-05 19:28:40 +04:00
all the integers and concatenate all the strings.
2020-02-12 01:29:12 +04:00
Here is an example where the keys are concatenated and the values are
summed up.
```pascaligo group=d
function sum_map (var m : map (string, int)) : string * int is block {
var string_total : string := "";
var int_total : int := 0;
for key -> value in map m block {
string_total := string_total ^ key;
int_total := int_total + value
}
} with (string_total, int_total)
```
2020-02-05 19:28:40 +04:00
You can call the function `sum_map` defined above using the LIGO compiler
like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_map
'map ["1"->1; "2"->2; "3"->3]'
# Outputs: ( "123", 6 )
```
</Syntax>