More updates to the documentation. Synced the new reference page.
This commit is contained in:
parent
1522a7d2e4
commit
127a85822f
@ -458,8 +458,7 @@ let force_access = ((key, moves) : (address, register)) : move => {
|
||||
### Updating a Map
|
||||
|
||||
Given a map, we may want to add a new binding, remove one, or modify
|
||||
one by changing the value associated to an already existing key. We
|
||||
may even want to retain the key but not the associated value. All
|
||||
one by changing the value associated to an already existing key. All
|
||||
those operations are called *updates*.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
@ -733,21 +732,18 @@ Here is how we define a big map:
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_maps
|
||||
type move is int * int
|
||||
|
||||
type register is big_map (address, move)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=big_maps
|
||||
type move = int * int
|
||||
|
||||
type register = (address, move) big_map
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=big_maps
|
||||
type move = (int, int);
|
||||
|
||||
type register = big_map (address, move);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
@ -789,9 +785,9 @@ const moves : register =
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
|
||||
```
|
||||
|
||||
Notice the right arrow `->` between the key and its value and the -->
|
||||
semicolon separating individual map entries. The value annotation -->
|
||||
`("<string value>" : address)` means that we cast a string into an -->
|
||||
Notice the right arrow `->` between the key and its value and the
|
||||
semicolon separating individual map entries. The value annotation
|
||||
`("<string value>" : address)` means that we cast a string into an
|
||||
address. -->
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
@ -213,7 +213,7 @@ let c : tez = 5n * 5mutez;
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Division
|
||||
## Euclidean Division
|
||||
|
||||
In LIGO you can divide `int`, `nat`, and `tez`. Here is how:
|
||||
|
||||
@ -243,6 +243,46 @@ let c : nat = 10mutez / 3mutez;
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
LIGO also allows you to compute the remainder of the Euclidean
|
||||
division. In LIGO, it is a natural number.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=d
|
||||
const a : int = 120
|
||||
const b : int = 9
|
||||
const rem1 : nat = a mod b // 3
|
||||
const c : nat = 120n
|
||||
const rem2 : nat = c mod b // 3
|
||||
const d : nat = 9n
|
||||
const rem3 : nat = c mod d // 3
|
||||
const rem4 : nat = a mod d // 3
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=d
|
||||
let a : int = 120
|
||||
let b : int = 9
|
||||
let rem1 : nat = a mod b // 3
|
||||
let c : nat = 120n
|
||||
let rem2 : nat = c mod b // 3
|
||||
let d : nat = 9n
|
||||
let rem3 : nat = c mod d // 3
|
||||
let rem4 : nat = a mod d // 3
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=d
|
||||
let a : int = 120;
|
||||
let b : int = 9;
|
||||
let rem1 : nat = a mod b; // 3
|
||||
let c : nat = 120n;
|
||||
let rem2 : nat = c mod b; // 3
|
||||
let d : nat = 9n;
|
||||
let rem3 : nat = c mod d; // 3
|
||||
let rem4 : nat = a mod d; // 3
|
||||
```
|
||||
|
||||
## From `int` to `nat` and back
|
||||
|
||||
You can *cast* an `int` to a `nat` and vice versa. Here is how:
|
||||
@ -265,7 +305,6 @@ let b : nat = abs (1)
|
||||
let a : int = int (1n);
|
||||
let b : nat = abs (1);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Checking a `nat`
|
||||
|
@ -124,7 +124,6 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
### Adding to Lists
|
||||
|
||||
Lists can be augmented by adding an element before the head (or, in
|
||||
@ -176,15 +175,16 @@ There are three kinds of functional iterations over LIGO lists: the
|
||||
*iterated operation*, the *map operation* (not to be confused with the
|
||||
*map data structure*) and the *fold operation*.
|
||||
|
||||
|
||||
#### Iterated Operation over Lists
|
||||
|
||||
The first, the *iterated operation*, is an iteration over the list
|
||||
with a unit return value. It is useful to enforce certain invariants
|
||||
on the element of a list, or fail. For example you might want to check
|
||||
that each value inside of a list is within a certain range, and fail
|
||||
otherwise. The predefined functional iterator implementing the
|
||||
iterated operation over lists is called `List.iter`.
|
||||
on the element of a list, or fail.
|
||||
|
||||
For example you might want to check that each value inside of a list
|
||||
is within a certain range, and fail otherwise. The predefined
|
||||
functional iterator implementing the iterated operation over lists is
|
||||
called `List.iter`.
|
||||
|
||||
In the following example, a list is iterated to check that all its
|
||||
elements (integers) are strictly greater than `3`.
|
||||
@ -305,7 +305,7 @@ let sum_of_elements : int = List.fold (sum, my_list, 0);
|
||||
Sets are unordered collections of values of the same type, like lists
|
||||
are ordered collections. Like the mathematical sets and lists, sets
|
||||
can be empty and, if not, elements of sets in LIGO are *unique*,
|
||||
whereas they can be repeated in a list.
|
||||
whereas they can be repeated in a *list*.
|
||||
|
||||
### Empty Sets
|
||||
|
||||
@ -447,6 +447,9 @@ elements in a given set as follows.
|
||||
```pascaligo group=sets
|
||||
const cardinal : nat = Set.size (my_set)
|
||||
```
|
||||
|
||||
> Note that `size` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=sets
|
||||
@ -636,12 +639,9 @@ traversal of the data structure is over. The predefined fold over sets
|
||||
is called `Set.fold`.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
|
||||
```pascaligo group=sets
|
||||
function sum (const acc : int; const i : int): int is acc + i
|
||||
|
||||
const sum_of_elements : int = Set.fold (sum, my_set, 0)
|
||||
```
|
||||
|
||||
@ -659,18 +659,14 @@ function loop (const s : set (int)) : int is block {
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=sets
|
||||
let sum (acc, i : int * int) : int = acc + i
|
||||
|
||||
let sum_of_elements : int = Set.fold sum my_set 0
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=sets
|
||||
let sum = ((acc, i) : (int, int)) : int => acc + i;
|
||||
|
||||
let sum_of_elements : int = Set.fold (sum, my_set, 0);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
@ -1,60 +1,66 @@
|
||||
---
|
||||
id: big-map-reference
|
||||
title: Big Map — Scalable Maps
|
||||
title: Big Maps — Scalable Maps
|
||||
---
|
||||
|
||||
## Defining A Big Map Type
|
||||
Ordinary maps are fine for contracts with a finite lifespan or a
|
||||
bounded number of users. For many contracts however, the intention is
|
||||
to have a map holding *many* entries, potentially millions of
|
||||
them. The cost of loading those entries into the environment each time
|
||||
a user executes the contract would eventually become too expensive
|
||||
were it not for *big maps*. Big maps are a data structure offered by
|
||||
Michelson which handles the scaling concerns for us. In LIGO, the
|
||||
interface for big maps is analogous to the one used for ordinary maps.
|
||||
|
||||
# Declaring a Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=big_map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_maps
|
||||
type move is int * int
|
||||
type register is big_map (address, move)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=big_map
|
||||
```cameligo group=big_maps
|
||||
type move = int * int
|
||||
type register = (address, move) big_map
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=big_map
|
||||
```reasonligo group=big_maps
|
||||
type move = (int, int);
|
||||
type register = big_map (address, move);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Creating an Empty Big Map
|
||||
|
||||
Create an empty big map.
|
||||
# Creating an Empty Big Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_map
|
||||
```pascaligo group=big_maps
|
||||
const empty : register = big_map []
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=big_map
|
||||
```cameligo group=big_maps
|
||||
let empty : register = Big_map.empty
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=big_map
|
||||
```reasonligo group=big_maps
|
||||
let empty : register = Big_map.empty
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Populating A Big Map
|
||||
# Creating a Non-empty Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
|
||||
```pascaligo group=big_map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_maps
|
||||
const moves : register =
|
||||
big_map [
|
||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
|
||||
@ -62,8 +68,7 @@ const moves: register =
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=big_map
|
||||
```cameligo group=big_maps
|
||||
let moves : register =
|
||||
Big_map.literal [
|
||||
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
|
||||
@ -71,67 +76,42 @@ let moves: register =
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=big_map
|
||||
```reasonligo group=big_maps
|
||||
let moves : register =
|
||||
Big_map.literal ([
|
||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Retrieving a Value in a Big Map
|
||||
|
||||
Retrieve the value associated with a particular key. This version
|
||||
returns an option which can either shift logic in response to a
|
||||
missing value or throw an error.
|
||||
# Accessing Values
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=big_map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_maps
|
||||
const my_balance : option (move) =
|
||||
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
The function is `Big_map.find_opt` whose type is `'key ->
|
||||
('key,'value) big_map) -> 'value option`. Recall that the function
|
||||
`Big_map.find_opt` must always be fully applied to its arguments. Here
|
||||
is an example:
|
||||
|
||||
```cameligo group=big_map
|
||||
```cameligo group=big_maps
|
||||
let my_balance : move option =
|
||||
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
The function is `Big_map.find_opt` whose type is `('key, ('key,
|
||||
'value) big_map) : 'value option`. Here is an example:
|
||||
|
||||
```reasonligo group=big_map
|
||||
```reasonligo group=big_maps
|
||||
let my_balance : option (move) =
|
||||
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, moves);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Updating a Binding in a Big Map
|
||||
|
||||
Given a map, we may want to add a new binding, remove one, or modify
|
||||
one by changing the value associated to an already existing key. We
|
||||
may even want to retain the key but not the associated value. All
|
||||
those operations are called *updates*.
|
||||
# Updating Big Maps
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--Pascaligo-->
|
||||
|
||||
The values of a PascaLIGO big map can be updated using the ordinary
|
||||
assignment syntax:
|
||||
|
||||
```pascaligo group=big_map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_maps
|
||||
function add (var m : register) : register is
|
||||
block {
|
||||
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
|
||||
@ -140,114 +120,45 @@ function add (var m : register) : register is
|
||||
const updated_map : register = add (moves)
|
||||
```
|
||||
|
||||
See further for the removal of bindings.
|
||||
|
||||
<!--Cameligo-->
|
||||
|
||||
In CameLIGO, you need the predefined function `Big_map.update` whose
|
||||
type is `'key -> 'value option -> ('key, 'value) big_map -> ('key,
|
||||
'value) big_map`. If the value (second argument) is `None`, then the
|
||||
binding is to be removed. Recall that the function `Big_map.update`
|
||||
must always be fully applied to its arguments. Here is an example:
|
||||
|
||||
```cameligo group=big_map
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=big_maps
|
||||
let updated_map : register =
|
||||
Big_map.update
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves
|
||||
```
|
||||
|
||||
<!--Reasonligo-->
|
||||
|
||||
In ReasonLIGO, you need the predefined function `Big_map.update` whose
|
||||
type is `('key, 'value option, ('key, 'value) big_map) : ('key,
|
||||
'value) big_map`. If the value (second componenat) is `None`, then the
|
||||
binding is to be removed. Here is an example:
|
||||
|
||||
```reasonligo group=big_map
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=big_maps
|
||||
let updated_map : register =
|
||||
Big_map.update
|
||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Adding a Binding to a Big Map
|
||||
|
||||
Add a key and its associated value to the big map.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
```pascaligo group=big_map
|
||||
function add (var m : register) : register is
|
||||
block {
|
||||
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
|
||||
} with m
|
||||
|
||||
const updated_map : register = add (moves)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
In CameLIGO, we use the predefined function `Big_map.add`, whose type
|
||||
is `'key -> 'value -> ('key, 'value) big_map -> ('key, 'value)
|
||||
big_map`. Recall that the function `Big_map.add` must always be fully
|
||||
applied to its arguments. Here is an example:
|
||||
|
||||
```cameligo group=big_map
|
||||
let add (m : register) : register =
|
||||
Map.add
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (4,9) m
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
In ReasonLIGO, we use the predefined function `Big_map.add`, whose
|
||||
type is `('key, 'value, ('key, 'value) big_map : ('key, 'value)
|
||||
big_map`. Here is an example:
|
||||
|
||||
```reasonligo group=big_map
|
||||
let add = (m : register) : register =>
|
||||
Map.add
|
||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (4,9), m);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Removing a Binding from a Big Map
|
||||
|
||||
Remove a key and its associated value from the big map.
|
||||
# Removing Bindings
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=big_map
|
||||
function delete (const key : address; var moves : register) : register is
|
||||
```pascaligo group=big_maps
|
||||
function rem (var m : register) : register is
|
||||
block {
|
||||
remove key from map moves
|
||||
} with moves
|
||||
remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) from map moves
|
||||
} with m
|
||||
|
||||
const updated_map : register = rem (moves)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
In CameLIGO, we use the predefined function `Big_map.remove` whose
|
||||
type is `'key -> ('key, 'value) big_map -> ('key, 'value)
|
||||
big_map`. Note that, despite being curried, the calls to that function
|
||||
must be complete. Here is an example:
|
||||
|
||||
```cameligo group=big_map
|
||||
let delete (key, moves : address * register) : register =
|
||||
Map.remove key moves
|
||||
```cameligo group=big_maps
|
||||
let updated_map : register =
|
||||
Map.remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
In ReasonLIGO, we use the predefined function `Big_map.remove` whose
|
||||
type is `('key, ('key, 'value) big_map) : ('key, 'value)
|
||||
big_map`. Here is an example:
|
||||
|
||||
```reasonligo group=big_map
|
||||
let delete = ((key, moves) : (address, register)) : register =>
|
||||
Map.remove (key, moves);
|
||||
```reasonligo group=big_maps
|
||||
let updated_map : register =
|
||||
Map.remove (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves)
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
id: current-reference
|
||||
title: Current - Things relating to the current execution context
|
||||
title: Tezos - Things relating to the current execution context
|
||||
---
|
||||
|
||||
## Current.balance() : tez
|
||||
# Tezos.balance
|
||||
|
||||
Get the balance for the contract.
|
||||
|
||||
@ -12,25 +12,35 @@ Get the balance for the contract.
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const p : unit; const s: tez) : list (operation) * tez is
|
||||
((nil : list(operation)), balance)
|
||||
((nil : list (operation)), Tezos.balance)
|
||||
```
|
||||
|
||||
> Note that `balance` and `Current.balance` are *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p, s : unit * tez) =
|
||||
([] : operation list), balance
|
||||
let main (p,s : unit * tez) = ([] : operation list), Tezos.balance
|
||||
```
|
||||
|
||||
> Note that `balance` and `Current.balance` are *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = ((p,s): (unit, tez)) => ([]: list(operation), balance);
|
||||
let main = ((p,s) : (unit, tez)) =>
|
||||
([]: list (operation), Tezos.balance);
|
||||
```
|
||||
|
||||
> Note that `balance` and `Current.balance` are *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.time() : timestamp
|
||||
## Tezos.now
|
||||
|
||||
Returns the current time as a [unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
|
||||
|
||||
In LIGO, timestamps are type compatible in operations with `int`(s). This lets you set e.g. time constraints for your smart contracts like this:
|
||||
In LIGO, timestamps are type compatible in operations with
|
||||
integers. This lets you set for instance time constraints for your
|
||||
smart contracts like this:
|
||||
|
||||
### Examples
|
||||
|
||||
@ -38,118 +48,134 @@ In LIGO, timestamps are type compatible in operations with `int`(s). This lets y
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=b
|
||||
const today: timestamp = now;
|
||||
const one_day: int = 86400;
|
||||
const today: timestamp = Tezos.now;
|
||||
const one_day: int = 86_400;
|
||||
const in_24_hrs: timestamp = today + one_day;
|
||||
const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp);
|
||||
const one_day_later: timestamp = some_date + one_day;
|
||||
```
|
||||
|
||||
> Note that `now` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=b
|
||||
let today: timestamp = Current.time
|
||||
let one_day: int = 86400
|
||||
let today: timestamp = Tezos.now
|
||||
let one_day: int = 86_400
|
||||
let in_24_hrs: timestamp = today + one_day
|
||||
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp)
|
||||
let one_day_later: timestamp = some_date + one_day
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=b
|
||||
let today: timestamp = Current.time;
|
||||
let one_day: int = 86400;
|
||||
let today: timestamp = Tezos.now;
|
||||
let one_day: int = 86_400;
|
||||
let in_24_hrs: timestamp = today + one_day;
|
||||
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp);
|
||||
let one_day_later: timestamp = some_date + one_day;
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
#### 24 hours ago
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=c
|
||||
const today: timestamp = now;
|
||||
const one_day: int = 86400;
|
||||
const today: timestamp = Tezos.now;
|
||||
const one_day: int = 86_400;
|
||||
const in_24_hrs: timestamp = today - one_day;
|
||||
```
|
||||
|
||||
> Note that `now` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=c
|
||||
let today: timestamp = Current.time
|
||||
let one_day: int = 86400
|
||||
let today: timestamp = Tezos.now
|
||||
let one_day: int = 86_400
|
||||
let in_24_hrs: timestamp = today - one_day
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=c
|
||||
let today: timestamp = Current.time;
|
||||
let one_day: int = 86400;
|
||||
let today: timestamp = Tezos.now;
|
||||
let one_day: int = 86_400;
|
||||
let in_24_hrs: timestamp = today - one_day;
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
#### Comparing timestamps
|
||||
#### Comparing Timestamps
|
||||
|
||||
You can also compare timestamps using the same comparison operators as for numbers:
|
||||
You can also compare timestamps using the same comparison operators as
|
||||
for numbers
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=c
|
||||
const not_tommorow: bool = (now = in_24_hrs)
|
||||
const not_tommorow: bool = (Tezos.now = in_24_hrs)
|
||||
```
|
||||
|
||||
> Note that `now` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=c
|
||||
let not_tomorrow: bool = (Current.time = in_24_hrs)
|
||||
let not_tomorrow: bool = (Tezos.now = in_24_hrs)
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=c
|
||||
let not_tomorrow: bool = (Current.time == in_24_hrs);
|
||||
let not_tomorrow: bool = (Tezos.now == in_24_hrs);
|
||||
```
|
||||
|
||||
> Note that `Current.time` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## Current.amount() : tez
|
||||
## Amount
|
||||
|
||||
Get the amount of tez provided by the sender to complete this transaction.
|
||||
Get the amount of tez provided by the sender to complete this
|
||||
transaction.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function check (const p: unit) : int is
|
||||
begin
|
||||
var result : int := 0;
|
||||
if amount = 100tz then
|
||||
result := 42
|
||||
else
|
||||
result := 0
|
||||
end with result
|
||||
function threshold (const p : unit) : int is
|
||||
if Tezos.amount = 100tz then 42 else 0
|
||||
```
|
||||
|
||||
> Note that `amount` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let check_ (p: unit) : int = if Current.amount = 100tz then 42 else 0
|
||||
let threshold (p : unit) : int = if Tezos.amount = 100tz then 42 else 0
|
||||
```
|
||||
|
||||
> Note that `Current.amount` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let check_ = (p: unit) : int =>
|
||||
if (Current.amount == 100tz) {
|
||||
42;
|
||||
}
|
||||
else {
|
||||
0;
|
||||
};
|
||||
let threshold = (p : unit) : int =>
|
||||
if (Tezos.amount == 100tz) { 42; } else { 0; };
|
||||
```
|
||||
|
||||
> Note that `Current.amount` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.sender() : address
|
||||
## Sender
|
||||
|
||||
Get the address that initiated the current transaction.
|
||||
|
||||
@ -157,52 +183,67 @@ Get the address that initiated the current transaction.
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const p: unit) : address is sender
|
||||
function main (const p : unit) : address is Tezos.sender
|
||||
```
|
||||
|
||||
> Note that `sender` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p: unit) : address = Current.sender
|
||||
let main (p: unit) : address = Tezos.sender
|
||||
```
|
||||
|
||||
> Note that `Current.sender` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = (p: unit) : address => Current.sender;
|
||||
let main = (p : unit) : address => Tezos.sender;
|
||||
```
|
||||
|
||||
> Note that `Current.sender` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.address(c: a' contract) : address
|
||||
|
||||
Get the address associated with a `contract`.
|
||||
## Address
|
||||
|
||||
Get the address associated with a value of type `contract`.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const p : key_hash) : address is block {
|
||||
const c : contract(unit) = implicit_account(p) ;
|
||||
} with address(c)
|
||||
const c : contract (unit) = Tezos.implicit_account (p)
|
||||
} with Tezos.address(c)
|
||||
```
|
||||
|
||||
> Note that `implicit_account` and `address` are *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p : key_hash) =
|
||||
let c : unit contract = Current.implicit_account p in
|
||||
Current.address c
|
||||
let c : unit contract = Tezos.implicit_account p
|
||||
in Tezos.address c
|
||||
```
|
||||
|
||||
> Note that `Current.implicit_account` and `Current.address` are
|
||||
> *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = (p : key_hash) : address => {
|
||||
let c : contract(unit) = Current.implicit_account(p) ;
|
||||
Current.address(c) ;
|
||||
let c : contract (unit) = Tezos.implicit_account (p);
|
||||
Tezos.address (c);
|
||||
};
|
||||
```
|
||||
|
||||
> Note that `Current.implicit_account` and `Current.address` are
|
||||
> *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.self_address() : address
|
||||
## Self Address
|
||||
|
||||
Get the address of the currently running contract.
|
||||
|
||||
@ -210,84 +251,116 @@ Get the address of the currently running contract.
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const p: unit) : address is self_address
|
||||
function main (const p : unit) : address is Tezos.self_address
|
||||
```
|
||||
|
||||
> Note that `self_address` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p: unit) : address = Current.self_address
|
||||
let main (p : unit) : address = Tezos.self_address
|
||||
```
|
||||
|
||||
> Note that `Current.self_address` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = (p: unit): address => Current.self_address;
|
||||
let main = (p : unit) : address => Tezos.self_address;
|
||||
```
|
||||
|
||||
> Note that `Current.self_address` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.implicit_account(p: key_hash) : a' contract
|
||||
## Implicit Account
|
||||
|
||||
Get the default contract associated with an on-chain keypair. This contract
|
||||
doesn't execute code, instead it exists to receive money on behalf of a keys
|
||||
owner.
|
||||
Get the default contract associated with an on-chain key-pair. This
|
||||
contract does not execute code, instead it exists to receive tokens on
|
||||
behalf of a key's owner.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const kh: key_hash) : contract(unit) is implicit_account(kh)
|
||||
function main (const kh: key_hash) : contract (unit) is
|
||||
Tezos.implicit_account (kh)
|
||||
```
|
||||
|
||||
> Note that `implicit_account` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (kh: key_hash) : unit contract = Current.implicit_account kh
|
||||
let main (kh : key_hash) : unit contract = Tezos.implicit_account kh
|
||||
```
|
||||
|
||||
> Note that `Current.implicit_account` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = (kh: key_hash): contract(unit) => Current.implicit_account(kh);
|
||||
let main = (kh : key_hash): contract (unit) =>
|
||||
Tezos.implicit_account (kh);
|
||||
```
|
||||
|
||||
> Note that `Current.implicit_account` is *deprecated*.
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.source() : address
|
||||
## Source
|
||||
|
||||
Get the _originator_ of the current transaction. That is, if a chain of transactions
|
||||
led to the current execution get the address that began the chain. Not to be confused
|
||||
with `Current.sender`, which gives the address of the contract or user which directly
|
||||
caused the current transaction.
|
||||
Get the _originator_ (address) of the current transaction. That is, if
|
||||
a chain of transactions led to the current execution get the address
|
||||
that began the chain. Not to be confused with `Tezos.sender`, which
|
||||
gives the address of the contract or user which directly caused the
|
||||
current transaction.
|
||||
|
||||
> ⚠️
|
||||
> There are a few caveats you should keep in mind before using `SOURCE` over `SENDER`:
|
||||
> ⚠️ There are a few caveats you should keep in mind before using
|
||||
> `Tezos.source` over `Tezos.sender`:
|
||||
>
|
||||
> 1. SOURCE will never be a contract, so if you want to allow contracts (multisigs etc) to operate your contract, you need to use SENDER
|
||||
> 2. https://vessenes.com/tx-origin-and-ethereum-oh-my/ -- in general it is somewhat unsafe to assume that SOURCE understands everything that's going to happen in a transaction. If SOURCE transfers to a malicious (or sufficiently attackable) contract, that contract might potentially transfer to yours, without SOURCE's consent. So if you are using SOURCE for authentication, you risk being confused. A good historical example of this is bakers paying out delegation rewards. Naive bakers did (and probably still do) just use tezos-client to transfer to whatever KT1 delegates they had, even if those KT1 were malicious scripts.
|
||||
> 1. `Tezos.source` will never be a contract, so if you want to allow
|
||||
> contracts (multisigs etc) to operate your contract, you need to
|
||||
> use `Tezos.sender`
|
||||
> 2. https://vessenes.com/tx-origin-and-ethereum-oh-my/ -- in general
|
||||
> it is somewhat unsafe to assume that `Tezos.source` understands
|
||||
> everything that is going to happen in a transaction. If
|
||||
> `Tezos.source` transfers to a malicious (or sufficiently
|
||||
> attackable) contract, that contract might potentially transfer to
|
||||
> yours, without `Tezos.source`'s consent. So if you are using
|
||||
> `Tezos.source` for authentication, you risk being confused. A
|
||||
> good historical example of this is bakers paying out delegation
|
||||
> rewards. Naive bakers did (and probably still do) just use
|
||||
> tezos-client to transfer to whatever KT1 delegates they had, even
|
||||
> if those KT1 were malicious scripts.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function main (const p: unit) : address is source
|
||||
function main (const p: unit) : address is Tezos.source
|
||||
```
|
||||
|
||||
> Note that `source` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p: unit) : address = Current.source
|
||||
let main (p : unit) : address = Tezos.source
|
||||
```
|
||||
|
||||
> Note that `Current.source` is *deprecated*.
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = (p: unit) : address => Current.source;
|
||||
let main = (p : unit) : address => Tezos.source;
|
||||
```
|
||||
|
||||
> Note that `Current.source` is *deprecated*.
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Current.failwith(error_message: string) : a'
|
||||
## Failwith
|
||||
|
||||
Cause the contract to fail with an error message.
|
||||
|
||||
> ⚠ Using this currently requires a type annotation on the failwith to unify it
|
||||
> with the type of whatever other code branch it's on.
|
||||
> ⚠ Using this currently requires in general a type annotation on the
|
||||
> `failwith` call.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
@ -295,25 +368,20 @@ Cause the contract to fail with an error message.
|
||||
```pascaligo
|
||||
function main (const p : int; const s : unit) : list (operation) * unit is
|
||||
block {
|
||||
if p > 10 then failwith("fail") else skip;
|
||||
if p > 10 then failwith ("Failure.") else skip
|
||||
}
|
||||
with ((nil : list (operation)), s)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let main (p,s: unit * unit) =
|
||||
if true then failwith "This contract always fails" else ()
|
||||
let main (p,s : int * unit) = if p > 10 then failwith "Failure."
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let main = ((p,s): (unit, unit)) =>
|
||||
if (true) {
|
||||
failwith("This contract always fails");
|
||||
} else {
|
||||
();
|
||||
};
|
||||
let main = ((p,s) : (int, unit)) =>
|
||||
if (p > 10) { failwith ("Failure."); };
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
id: list-reference
|
||||
title: List — Linear Collections
|
||||
title: Lists — Linear Collections
|
||||
---
|
||||
|
||||
Lists are linear collections of elements of the same type. Linear
|
||||
@ -11,7 +11,7 @@ called the *head*, and the sub-list after the head is called the
|
||||
*tail*. For those familiar with algorithmic data structure, you can
|
||||
think of a list a *stack*, where the top is written on the left.
|
||||
|
||||
## Defining Lists
|
||||
# Defining Lists
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
@ -34,7 +34,7 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
### Adding to Lists
|
||||
# Adding to Lists
|
||||
|
||||
Lists can be augmented by adding an element before the head (or, in
|
||||
terms of stack, by *pushing an element on top*).
|
||||
@ -61,7 +61,7 @@ let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2]
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
### Functional Iteration over Lists
|
||||
# Functional Iteration over Lists
|
||||
|
||||
A *functional iterator* is a function that traverses a data structure
|
||||
and calls in turn a given function over the elements of that structure
|
||||
@ -72,7 +72,7 @@ There are three kinds of functional iterations over LIGO lists: the
|
||||
*iterated operation*, the *map operation* (not to be confused with the
|
||||
*map data structure*) and the *fold operation*.
|
||||
|
||||
#### Iterated Operation over Lists
|
||||
## Iterated Operation over Lists
|
||||
|
||||
The first, the *iterated operation*, is an iteration over the list
|
||||
with a unit return value. It is useful to enforce certain invariants
|
||||
@ -86,9 +86,13 @@ on the element of a list, or fail.
|
||||
function iter_op (const l : list (int)) : unit is
|
||||
block {
|
||||
function iterated (const i : int) : unit is
|
||||
if i > 2 then Unit else (failwith ("Below range.") : unit)
|
||||
} with list_iter (iterated, l)
|
||||
if i > 3 then Unit else (failwith ("Below range.") : unit)
|
||||
} with List.iter (iterated, l)
|
||||
```
|
||||
|
||||
> Note that `list_iter` is *deprecated*.
|
||||
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=lists
|
||||
@ -108,7 +112,7 @@ let iter_op = (l : list (int)) : unit => {
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
#### Mapped Operation over Lists
|
||||
## Mapped Operation over Lists
|
||||
|
||||
We may want to change all the elements of a given list by applying to
|
||||
them a function. This is called a *map operation*, not to be confused
|
||||
@ -122,9 +126,11 @@ with the map data structure.
|
||||
function increment (const i : int): int is i + 1
|
||||
|
||||
// Creates a new list with all elements incremented by 1
|
||||
const plus_one : list (int) = list_map (increment, larger_list)
|
||||
const plus_one : list (int) = List.map (increment, larger_list)
|
||||
```
|
||||
|
||||
> Note that `list_map` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=lists
|
||||
@ -144,7 +150,8 @@ let plus_one : list (int) = List.map (increment, larger_list);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
#### Folded Operation over Lists
|
||||
|
||||
## Folded Operation over Lists
|
||||
|
||||
A *folded operation* is the most general of iterations. The folded
|
||||
function takes two arguments: an *accumulator* and the structure
|
||||
@ -158,9 +165,11 @@ traversal of the data structure is over.
|
||||
|
||||
```pascaligo group=lists
|
||||
function sum (const acc : int; const i : int): int is acc + i
|
||||
const sum_of_elements : int = list_fold (sum, my_list, 0)
|
||||
const sum_of_elements : int = List.fold (sum, my_list, 0)
|
||||
```
|
||||
|
||||
> Note that `list_fold` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=lists
|
||||
@ -176,7 +185,7 @@ let sum_of_elements : int = List.fold (sum, my_list, 0);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## List Length
|
||||
# List Length
|
||||
|
||||
Get the number of elements in a list.
|
||||
|
||||
@ -187,6 +196,8 @@ Get the number of elements in a list.
|
||||
function size_of (const l : list (int)) : nat is List.length (l)
|
||||
```
|
||||
|
||||
> Note that `size` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let size_of (l : int list) : nat = List.length l
|
||||
@ -198,112 +209,3 @@ let size_of = (l : list (int)) : nat => List.length (l);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## List.map(map_function: a' -> b', lst: a' list) : 'b list
|
||||
|
||||
Apply an operation defined by `map_function` to each element of a list
|
||||
and return a list of the modified elements.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=b
|
||||
function increment(const i: int): int is i + 1;
|
||||
// Creates a new list with elements incremented by 1
|
||||
const incremented_list: list(int) = list_map(increment, list 1; 2; 3; end );
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=b
|
||||
let increment (i: int) : int = i + 1
|
||||
(* Creates a new list with elements incremented by 1 *)
|
||||
let incremented_list: int list = List.map increment [1; 2; 3]
|
||||
```
|
||||
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=b
|
||||
let increment = (i: int): int => i + 1;
|
||||
(* Creates a new list with elements incremented by 1 *)
|
||||
let incremented_list: list(int) = List.map(increment, [1, 2, 3]);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## List.iter(iter_function: a' -> unit, lst: a' list) : unit
|
||||
|
||||
Apply a side effecting function `iter_function` to each element of a list with no
|
||||
return value. This is useful for asserting that each element of a list satisfies
|
||||
a particular property.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
function iter_op (const s : list(int)) : int is
|
||||
begin
|
||||
var r : int := 0 ;
|
||||
function aggregate (const i : int) : unit is
|
||||
begin
|
||||
r := r + i ;
|
||||
end with unit ;
|
||||
list_iter(aggregate, s) ;
|
||||
end with r
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let iter_op (s : int list) : unit =
|
||||
let do_nothing = fun (_: int) -> unit
|
||||
in List.iter do_nothing s
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let iter_op = (s: list(int)): unit => {
|
||||
let do_nothing = (z: int) => unit;
|
||||
List.iter(do_nothing, s);
|
||||
};
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## List.fold(fold_function: (a' * a') -> a', lst: a' list, acc: a') : 'a
|
||||
|
||||
Combine the elements of a list into one value using the operation defined by
|
||||
`fold_function'. For example, you could define summation by folding a list of
|
||||
integers. Starting with some initial accumulator value `acc`, the fold:
|
||||
|
||||
1. Consumes an element of the list.
|
||||
2. Passes the accumulator value to `fold_function` along with the element to produce
|
||||
a new accumulated value.
|
||||
3. The new accumulated value replaces the previous one.
|
||||
4. IF there are still elements in the list go back to 1, ELSE return the accumulator
|
||||
|
||||
Summation would be defined then by using a `fold_function` that takes two integers and
|
||||
adds them together. Each step of the fold would consume an element from the list
|
||||
and add it to the total until you've summed over the list.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=b
|
||||
function sum(const result: int; const i: int): int is result + i;
|
||||
const sum_of_a_list: int = list_fold(sum, list 1; 2; 3; end, 0);
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=b
|
||||
let sum (result, i: int * int) : int = result + i
|
||||
let sum_of_a_list: int = List.fold sum [1; 2; 3] 0
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=b
|
||||
let sum = ((result, i): (int, int)): int => result + i;
|
||||
let sum_of_a_list: int = List.fold(sum, [1, 2, 3], 0);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
@ -1,60 +1,62 @@
|
||||
---
|
||||
id: map-reference
|
||||
title: Map
|
||||
title: Maps
|
||||
---
|
||||
|
||||
## Defining A Map Type
|
||||
*Maps* are a data structure which associate values of the same type to
|
||||
values of the same type. The former are called *key* and the latter
|
||||
*values*. Together they make up a *binding*. An additional requirement
|
||||
is that the type of the keys must be *comparable*, in the Michelson
|
||||
sense.
|
||||
|
||||
# Declaring a Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=map
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=maps
|
||||
type move is int * int
|
||||
type register is map (address, move)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=map
|
||||
```cameligo group=maps
|
||||
type move = int * int
|
||||
type register = (address, move) map
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=map
|
||||
```reasonligo group=maps
|
||||
type move = (int, int);
|
||||
type register = map (address, move);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Creating an Empty Map
|
||||
|
||||
Create an empty map.
|
||||
# Creating an Empty Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=map
|
||||
```pascaligo group=maps
|
||||
const empty : register = map []
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=map
|
||||
```cameligo group=maps
|
||||
let empty : register = Map.empty
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=map
|
||||
```reasonligo group=maps
|
||||
let empty : register = Map.empty
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Populating A Map
|
||||
# Creating a Non-empty Map
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
|
||||
```pascaligo group=map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=maps
|
||||
const moves : register =
|
||||
map [
|
||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
|
||||
@ -62,8 +64,7 @@ const moves: register =
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=map
|
||||
```cameligo group=maps
|
||||
let moves : register =
|
||||
Map.literal [
|
||||
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
|
||||
@ -71,141 +72,128 @@ let moves: register =
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=map
|
||||
```reasonligo group=maps
|
||||
let moves : register =
|
||||
Map.literal ([
|
||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Retrieving a Value in a Map
|
||||
|
||||
Retrieve the value associated with a particular key. This version
|
||||
returns an option which can either shift logic in response to a
|
||||
missing value or throw an error.
|
||||
# Accessing Map Bindings
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=map
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=maps
|
||||
const my_balance : option (move) =
|
||||
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
The function is `Map.find_opt` whose type is `'key ->
|
||||
('key,'value) map) -> 'value option`. Recall that the function
|
||||
`Map.find_opt` must always be fully applied to its arguments. Here
|
||||
is an example:
|
||||
|
||||
```cameligo group=map
|
||||
```cameligo group=maps
|
||||
let my_balance : move option =
|
||||
Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
The function is `Map.find_opt` whose type is `('key, ('key,
|
||||
'value) map) : 'value option`. Here is an example:
|
||||
|
||||
```reasonligo group=map
|
||||
```reasonligo group=maps
|
||||
let my_balance : option (move) =
|
||||
Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, moves);
|
||||
Map.find_opt (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), moves);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Updating a Binding in a Map
|
||||
|
||||
Given a map, we may want to add a new binding, remove one, or modify
|
||||
one by changing the value associated to an already existing key. We
|
||||
may even want to retain the key but not the associated value. All
|
||||
those operations are called *updates*.
|
||||
Notice how the value we read is an optional value: this is to force
|
||||
the reader to account for a missing key in the map. This requires
|
||||
*pattern matching*.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--Pascaligo-->
|
||||
|
||||
The values of a PascaLIGO map can be updated using the ordinary
|
||||
assignment syntax:
|
||||
|
||||
```pascaligo group=map
|
||||
function add (var m : register) : register is
|
||||
block {
|
||||
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
|
||||
} with m
|
||||
|
||||
const updated_map : register = add (moves)
|
||||
```
|
||||
|
||||
See further for the removal of bindings.
|
||||
|
||||
<!--Cameligo-->
|
||||
|
||||
In CameLIGO, you need the predefined function `Map.update` whose
|
||||
type is `'key -> 'value option -> ('key, 'value) map -> ('key,
|
||||
'value) map`. If the value (second argument) is `None`, then the
|
||||
binding is to be removed. Recall that the function `Map.update`
|
||||
must always be fully applied to its arguments. Here is an example:
|
||||
|
||||
```cameligo group=map
|
||||
let updated_map : register =
|
||||
Map.update
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves
|
||||
```
|
||||
|
||||
<!--Reasonligo-->
|
||||
|
||||
In ReasonLIGO, you need the predefined function `Map.update` whose
|
||||
type is `('key, 'value option, ('key, 'value) map) : ('key,
|
||||
'value) map`. If the value (second componenat) is `None`, then the
|
||||
binding is to be removed. Here is an example:
|
||||
|
||||
```reasonligo group=map
|
||||
let updated_map : register =
|
||||
Map.update
|
||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Adding a Binding to a Map
|
||||
|
||||
Add a key and its associated value to the map.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
```pascaligo group=map
|
||||
function add (var m : register) : register is
|
||||
block {
|
||||
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
|
||||
} with m
|
||||
|
||||
const updated_map : register = add (moves)
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=maps
|
||||
function force_access (const key : address; const moves : register) : move is
|
||||
case moves[key] of
|
||||
Some (move) -> move
|
||||
| None -> (failwith ("No move.") : move)
|
||||
end
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=maps
|
||||
let force_access (key, moves : address * register) : move =
|
||||
match Map.find_opt key moves with
|
||||
Some move -> move
|
||||
| None -> (failwith "No move." : move)
|
||||
```
|
||||
|
||||
In CameLIGO, we use the predefined function `Map.add`, whose type
|
||||
is `'key -> 'value -> ('key, 'value) map -> ('key, 'value)
|
||||
map`. Recall that the function `Map.add` must always be fully
|
||||
applied to its arguments. Here is an example:
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=maps
|
||||
let force_access = ((key, moves) : (address, register)) : move => {
|
||||
switch (Map.find_opt (key, moves)) {
|
||||
| Some (move) => move
|
||||
| None => failwith ("No move.") : move
|
||||
}
|
||||
};
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
```cameligo group=map
|
||||
# Updating a Map
|
||||
|
||||
Given a map, we may want to add a new binding, remove one, or modify
|
||||
one by changing the value associated to an already existing key. All
|
||||
those operations are called *updates*.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=maps
|
||||
function assign (var m : register) : register is
|
||||
block {
|
||||
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
|
||||
} with m
|
||||
```
|
||||
|
||||
If multiple bindings need to be updated, PascaLIGO offers a *patch
|
||||
instruction* for maps, similar to that for records.
|
||||
|
||||
```pascaligo group=maps
|
||||
function assignments (var m : register) : register is
|
||||
block {
|
||||
patch m with map [
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (4,9);
|
||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2)
|
||||
]
|
||||
} with m
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=maps
|
||||
let assign (m : register) : register =
|
||||
Map.update
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) m
|
||||
```
|
||||
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
|
||||
use `None` instead, that would have meant that the binding is removed.
|
||||
|
||||
As a particular case, we can only add a key and its associated value.
|
||||
|
||||
```cameligo group=maps
|
||||
let add (m : register) : register =
|
||||
Map.add
|
||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (4,9) m
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=maps
|
||||
let assign = (m : register) : register =>
|
||||
Map.update
|
||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m);
|
||||
```
|
||||
|
||||
In ReasonLIGO, we use the predefined function `Map.add`, whose
|
||||
type is `('key, 'value, ('key, 'value) map : ('key, 'value)
|
||||
map`. Here is an example:
|
||||
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
|
||||
use `None` instead, that would have meant that the binding is removed.
|
||||
|
||||
```reasonligo group=map
|
||||
As a particular case, we can only add a key and its associated value.
|
||||
|
||||
```reasonligo group=maps
|
||||
let add = (m : register) : register =>
|
||||
Map.add
|
||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (4,9), m);
|
||||
@ -213,14 +201,12 @@ let add = (m : register) : register =>
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Removing a Binding from a Map
|
||||
|
||||
Remove a key and its associated value from the map.
|
||||
To remove a binding from a map, we need its key.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=map
|
||||
```pascaligo group=maps
|
||||
function delete (const key : address; var moves : register) : register is
|
||||
block {
|
||||
remove key from map moves
|
||||
@ -228,47 +214,144 @@ function delete (const key : address; var moves : register) : register is
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
In CameLIGO, we use the predefined function `Map.remove` whose
|
||||
type is `'key -> ('key, 'value) map -> ('key, 'value)
|
||||
map`. Note that, despite being curried, the calls to that function
|
||||
must be complete. Here is an example:
|
||||
|
||||
```cameligo group=map
|
||||
```cameligo group=maps
|
||||
let delete (key, moves : address * register) : register =
|
||||
Map.remove key moves
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
In ReasonLIGO, we use the predefined function `Map.remove` whose
|
||||
type is `('key, ('key, 'value) map) : ('key, 'value)
|
||||
map`. Here is an example:
|
||||
|
||||
```reasonligo group=map
|
||||
```reasonligo group=maps
|
||||
let delete = ((key, moves) : (address, register)) : register =>
|
||||
Map.remove (key, moves);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Getting the Size of a Map
|
||||
|
||||
The size of a map is its number of bindings.
|
||||
# Functional Iteration over Maps
|
||||
|
||||
A *functional iterator* is a function that traverses a data structure
|
||||
and calls in turn a given function over the elements of that structure
|
||||
to compute some value. Another approach is possible in PascaLIGO:
|
||||
*loops* (see the relevant section).
|
||||
|
||||
There are three kinds of functional iterations over LIGO maps: the
|
||||
*iterated operation*, the *map operation* (not to be confused with the
|
||||
*map data structure*) and the *fold operation*.
|
||||
|
||||
## Iterated Operation over Maps
|
||||
|
||||
The first, the *iterated operation*, is an iteration over the map with
|
||||
no return value: its only use is to produce side-effects. This can be
|
||||
useful if for example you would like to check that each value inside
|
||||
of a map is within a certain range, and fail with an error otherwise.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=map
|
||||
function size_of (const m : register) : nat is size (m)
|
||||
|
||||
```pascaligo group=maps
|
||||
function iter_op (const m : register) : unit is
|
||||
block {
|
||||
function iterated (const i : address; const j : move) : unit is
|
||||
if j.1 > 3 then Unit else (failwith ("Below range.") : unit)
|
||||
} with Map.iter (iterated, m)
|
||||
```
|
||||
|
||||
> Note that `map_iter` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=map
|
||||
let size_of (m : register) : nat = Map.size m
|
||||
|
||||
```cameligo group=maps
|
||||
let iter_op (m : register) : unit =
|
||||
let predicate = fun (i,j : address * move) -> assert (j.0 > 3)
|
||||
in Map.iter predicate m
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=map
|
||||
let size_of = (m : register): nat => Map.size (m);
|
||||
|
||||
```reasonligo group=maps
|
||||
let iter_op = (m : register) : unit => {
|
||||
let predicate = ((i,j) : (address, move)) => assert (j[0] > 3);
|
||||
Map.iter (predicate, m);
|
||||
};
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Map Operations over Maps
|
||||
|
||||
We may want to change all the bindings of a map by applying to them a
|
||||
function. This is called a *map operation*, not to be confused with
|
||||
the map data structure. The predefined functional iterator
|
||||
implementing the map operation over maps is called `Map.map`.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
|
||||
```pascaligo group=maps
|
||||
function map_op (const m : register) : register is
|
||||
block {
|
||||
function increment (const i : address; const j : move) : move is
|
||||
(j.0, j.1 + 1)
|
||||
} with Map.map (increment, m)
|
||||
```
|
||||
|
||||
> Note that `map_map` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=maps
|
||||
let map_op (m : register) : register =
|
||||
let increment = fun (i,j : address * move) -> j.0, j.1 + 1
|
||||
in Map.map increment m
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=maps
|
||||
let map_op = (m : register) : register => {
|
||||
let increment = ((i,j): (address, move)) => (j[0], j[1] + 1);
|
||||
Map.map (increment, m);
|
||||
};
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Folded Operations over Maps
|
||||
|
||||
A *folded operation* is the most general of iterations. The folded
|
||||
function takes two arguments: an *accumulator* and the structure
|
||||
*element* at hand, with which it then produces a new accumulator. This
|
||||
enables having a partial result that becomes complete when the
|
||||
traversal of the data structure is over.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
|
||||
```pascaligo group=maps
|
||||
function fold_op (const m : register) : int is
|
||||
block {
|
||||
function folded (const i : int; const j : address * move) : int is
|
||||
i + j.1.1
|
||||
} with Map.fold (folded, m, 5)
|
||||
```
|
||||
|
||||
> Note that `map_fold` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=maps
|
||||
let fold_op (m : register) : register =
|
||||
let folded = fun (i,j : int * (address * move)) -> i + j.1.1
|
||||
in Map.fold folded m 5
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=maps
|
||||
let fold_op = (m : register) : register => {
|
||||
let folded = ((i,j): (int, (address, move))) => i + j[1][1];
|
||||
Map.fold (folded, m, 5);
|
||||
};
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
@ -1,201 +1,220 @@
|
||||
---
|
||||
id: set-reference
|
||||
title: Set — Unordered unique collection of a type
|
||||
title: Sets — Unordered unique collection of a type
|
||||
---
|
||||
|
||||
## Defining a set
|
||||
Sets are unordered collections of values of the same type, like lists
|
||||
are ordered collections. Like the mathematical sets and lists, sets
|
||||
can be empty and, if not, elements of sets in LIGO are *unique*,
|
||||
whereas they can be repeated in a *list*.
|
||||
|
||||
# Empty Sets
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
type int_set is set (int);
|
||||
const my_set : int_set = set 1; 2; 3 end
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=sets
|
||||
const my_set : set (int) = set []
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
type int_set = int set
|
||||
let my_set : int_set =
|
||||
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
|
||||
```cameligo group=sets
|
||||
let my_set : int set = Set.empty
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
type int_set = set (int);
|
||||
let my_set : int_set =
|
||||
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
|
||||
```reasonligo group=sets
|
||||
let my_set : set (int) = Set.empty;
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## Set.mem(is_member: a', s: a' set) : bool
|
||||
|
||||
Check if a set `s` contains the element `is_member`.
|
||||
# Non-empty Sets
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
const contains_three : bool = my_set contains 3
|
||||
// or alternatively
|
||||
const contains_three_fn: bool = set_mem (3, my_set);
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=sets
|
||||
const my_set : set (int) = set [3; 2; 2; 1]
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
let contains_three: bool = Set.mem 3 my_set
|
||||
```
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
let contains_three: bool = Set.mem(3, my_set);
|
||||
```cameligo group=sets
|
||||
let my_set : int set =
|
||||
Set.add 3 (Set.add 2 (Set.add 2 (Set.add 1 (Set.empty : int set))))
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=sets
|
||||
let my_set : set (int) =
|
||||
Set.add (3, Set.add (2, Set.add (2, Set.add (1, Set.empty : set (int)))));
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## Set.empty() : a' set
|
||||
|
||||
Create a new empty set. Needs to be annotated with the set type.
|
||||
# Set Membership
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
const my_set: int_set = set end
|
||||
const my_set_2: int_set = set_empty
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=sets
|
||||
const contains_3 : bool = my_set contains 3
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
let my_set: int_set = (Set.empty: int set)
|
||||
```cameligo group=sets
|
||||
let contains_3 : bool = Set.mem 3 my_set
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
let my_set: int_set = (Set.empty: set (int));
|
||||
```reasonligo group=sets
|
||||
let contains_3 : bool = Set.mem (3, my_set);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Set.literal(element_list_literal: 'a list) : 'a set
|
||||
# Cardinal of Sets
|
||||
|
||||
Create a set from the elements of a list. Note that **you must pass a list literal**
|
||||
to this function, a variable will not work.
|
||||
The predefined function `Set.size` returns the number of
|
||||
elements in a given set as follows.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=sets
|
||||
const cardinal : nat = Set.size (my_set)
|
||||
```
|
||||
|
||||
> Note that `size` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=sets
|
||||
let cardinal : nat = Set.size my_set
|
||||
```
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=sets
|
||||
let cardinal : nat = Set.size (my_set);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
# Updating Sets
|
||||
|
||||
There are two ways to update a set, that is to add or remove from it.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
In PascaLIGO, either we create a new set from the given one, or we
|
||||
modify it in-place. First, let us consider the former way:
|
||||
```pascaligo group=sets
|
||||
const larger_set : set (int) = Set.add (4, my_set)
|
||||
const smaller_set : set (int) = Set.remove (3, my_set)
|
||||
```
|
||||
|
||||
> Note that `set_add` and `set_remove` are *deprecated*.
|
||||
|
||||
If we are in a block, we can use an instruction to modify the set
|
||||
bound to a given variable. This is called a *patch*. It is only
|
||||
possible to add elements by means of a patch, not remove any: it is
|
||||
the union of two sets.
|
||||
|
||||
```pascaligo group=sets
|
||||
function update (var s : set (int)) : set (int) is block {
|
||||
patch s with set [4; 7]
|
||||
} with s
|
||||
|
||||
const new_set : set (int) = update (my_set)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=sets
|
||||
let larger_set : int set = Set.add 4 my_set
|
||||
let smaller_set : int set = Set.remove 3 my_set
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=sets
|
||||
let larger_set : set (int) = Set.add (4, my_set);
|
||||
let smaller_set : set (int) = Set.remove (3, my_set);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
# Functional Iteration over Sets
|
||||
|
||||
A *functional iterator* is a function that traverses a data structure
|
||||
and calls in turn a given function over the elements of that structure
|
||||
to compute some value. Another approach is possible in PascaLIGO:
|
||||
*loops* (see the relevant section).
|
||||
|
||||
There are three kinds of functional iterations over LIGO maps: the
|
||||
*iterated operation*, the *mapped operation* (not to be confused with
|
||||
the *map data structure*) and the *folded operation*.
|
||||
|
||||
## Iterated Operation
|
||||
|
||||
The first, the *iterated operation*, is an iteration over the map with
|
||||
no return value: its only use is to produce side-effects. This can be
|
||||
useful if for example you would like to check that each value inside
|
||||
of a map is within a certain range, and fail with an error otherwise.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo group=sets
|
||||
function iter_op (const s : set (int)) : unit is
|
||||
block {
|
||||
function iterated (const i : int) : unit is
|
||||
if i > 2 then Unit else (failwith ("Below range.") : unit)
|
||||
} with Set.iter (iterated, s)
|
||||
```
|
||||
|
||||
> Note that `set_iter` is *deprecated*.
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=sets
|
||||
let iter_op (s : int set) : unit =
|
||||
let predicate = fun (i : int) -> assert (i > 3)
|
||||
in Set.iter predicate s
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=sets
|
||||
let iter_op = (s : set (int)) : unit => {
|
||||
let predicate = (i : int) => assert (i > 3);
|
||||
Set.iter (predicate, s);
|
||||
};
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Folded Operation
|
||||
|
||||
A *folded operation* is the most general of iterations. The folded
|
||||
function takes two arguments: an *accumulator* and the structure
|
||||
*element* at hand, with which it then produces a new accumulator. This
|
||||
enables having a partial result that becomes complete when the
|
||||
traversal of the data structure is over.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
<!--PascaLIGO-->
|
||||
```pascaligo
|
||||
const s_fb : set(string) = set [
|
||||
"foo" ;
|
||||
"bar" ;
|
||||
]
|
||||
```pascaligo group=sets
|
||||
function sum (const acc : int; const i : int): int is acc + i
|
||||
const sum_of_elements : int = Set.fold (sum, my_set, 0)
|
||||
```
|
||||
|
||||
> Note that `set_fold` is *deprecated*.
|
||||
|
||||
It is possible to use a *loop* over a set as well.
|
||||
|
||||
```pascaligo group=sets
|
||||
function loop (const s : set (int)) : int is block {
|
||||
var sum : int := 0;
|
||||
for element in set s block {
|
||||
sum := sum + element
|
||||
}
|
||||
} with sum
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo
|
||||
let literal_op (p: unit) : string set =
|
||||
Set.literal ["foo"; "bar"; "foobar"]
|
||||
```cameligo group=sets
|
||||
let sum (acc, i : int * int) : int = acc + i
|
||||
let sum_of_elements : int = Set.fold sum my_set 0
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo
|
||||
let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Set.add(addition: a', s: a' set) : a' set
|
||||
|
||||
Add the element `addition` to a set `s`.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
function add_op (const s : set(string)) : set(string) is
|
||||
begin skip end with set_add("foobar" , s)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
type int_set = int set
|
||||
let my_set : int_set =
|
||||
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
type int_set = set (int);
|
||||
let my_set : int_set =
|
||||
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Set.remove(removal: a', s: a' set) : a' set
|
||||
|
||||
Remove the element `removal` from a set `s`.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
const smaller_set: int_set = set_remove(3, my_set);
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
|
||||
```cameligo group=a
|
||||
let smaller_set: int_set = Set.remove 3 my_set
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
|
||||
```reasonligo group=a
|
||||
let smaller_set: int_set = Set.remove(3, my_set);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## Set.fold(folding_function: a' -> a' -> a', s: a' set, initial: a') : a'
|
||||
|
||||
Combine the elements of a set into a single value using a folding function.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
function sum(const result: int; const i: int): int is result + i;
|
||||
// Outputs 6
|
||||
const sum_of_a_set: int = set_fold(sum, my_set, 0);
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
let sum (result, i: int * int) : int = result + i
|
||||
let sum_of_a_set: int = Set.fold sum my_set 0
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
let sum = (result_i: (int, int)): int => result_i[0] + result_i[1];
|
||||
let sum_of_a_set: int = Set.fold(sum, my_set, 0);
|
||||
```reasonligo group=sets
|
||||
let sum = ((acc, i) : (int, int)) : int => acc + i;
|
||||
let sum_of_elements : int = Set.fold (sum, my_set, 0);
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Set.size(s: a' set) : nat
|
||||
|
||||
Get the number of elements in a set.
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Pascaligo-->
|
||||
```pascaligo group=a
|
||||
const set_size: nat = size (my_set)
|
||||
```
|
||||
|
||||
<!--CameLIGO-->
|
||||
```cameligo group=a
|
||||
let set_size: nat = Set.size my_set
|
||||
```
|
||||
|
||||
<!--ReasonLIGO-->
|
||||
```reasonligo group=a
|
||||
let set_size: nat = Set.size (my_set);
|
||||
```
|
||||
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
Loading…
Reference in New Issue
Block a user