Merge branch 'feature/doc-pascaligo-loop' into 'dev'
Some doc update for Ligo training See merge request ligolang/ligo!364
This commit is contained in:
commit
04381b9dcf
@ -5,63 +5,132 @@ title: Entrypoints, Contracts
|
|||||||
|
|
||||||
## Entrypoints
|
## Entrypoints
|
||||||
|
|
||||||
Each LIGO smart contract is essentially a single function, that has the following *(pseudo)* type signature:
|
Each LIGO smart contract is essentially a single main function, referring to the following types:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```
|
```pascaligo group=a
|
||||||
(const parameter: my_type, const store: my_store_type): (list(operation), my_store_type)
|
type parameter_t is unit
|
||||||
|
type storage_t is unit
|
||||||
|
type return_t is (list(operation) * storage_t)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
```
|
```cameligo group=a
|
||||||
(parameter, store: my_type * my_store_type) : operation list * my_store_type
|
type parameter_t = unit
|
||||||
|
type storage_t = unit
|
||||||
|
type return_t = (operation list * storage_t)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
|
```reasonligo group=a
|
||||||
|
type parameter_t = unit;
|
||||||
|
type storage_t = unit;
|
||||||
|
type return_t = (list(operation) , storage_t);
|
||||||
```
|
```
|
||||||
(parameter_store: (my_type, my_store_type)) : (list(operation), my_store_type)
|
|
||||||
```
|
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
This means that every smart contract needs at least one entrypoint function, here's an example:
|
Each main function receives two arguments:
|
||||||
|
- `parameter` - this is the parameter received in the invocation operation
|
||||||
|
- `storage` - this is the current (real) on-chain storage value
|
||||||
|
|
||||||
|
Storage can only be modified by running the smart contract entrypoint, which is responsible for returning a pair holding a list of operations, and a new storage.
|
||||||
|
|
||||||
|
Here is an example of a smart contract main function:
|
||||||
|
|
||||||
> 💡 The contract below literally does *nothing*
|
> 💡 The contract below literally does *nothing*
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
type parameter is unit;
|
function main(const parameter: parameter_t; const store: storage_t): return_t is
|
||||||
type store is unit;
|
((nil : list(operation)), store)
|
||||||
function main(const parameter: parameter; const store: store): (list(operation) * store) is
|
|
||||||
block { skip } with ((nil : list(operation)), store)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
```cameligo group=a
|
```cameligo group=a
|
||||||
type parameter = unit
|
let main (parameter, store: parameter_t * storage_t) : return_t =
|
||||||
type store = unit
|
|
||||||
let main (parameter, store: parameter * store) : operation list * store =
|
|
||||||
(([]: operation list), store)
|
(([]: operation list), store)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
```reasonligo group=a
|
```reasonligo group=a
|
||||||
type parameter = unit;
|
let main = ((parameter, store): (parameter_t, storage_t)) : return_t => {
|
||||||
type store = unit;
|
|
||||||
let main = ((parameter, store): (parameter, store)) : (list(operation), store) => {
|
|
||||||
(([]: list(operation)), store);
|
(([]: list(operation)), store);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
Each entrypoint function receives two arguments:
|
A contract entrypoints are the constructors of the parameter type (variant) and you must use pattern matching (`case`, `match`, `switch`) on the parameter in order to associate each entrypoint to its corresponding handler.
|
||||||
- `parameter` - this is the parameter received in the invocation operation
|
|
||||||
- `storage` - this is the current (real) on-chain storage value
|
|
||||||
|
|
||||||
Storage can only be modified by running the smart contract entrypoint, which is responsible for returning a list of operations, and a new storage at the end of it's execution.
|
To access the 'entrypoints' of a contract, we define a main function whose parameter is a variant type with constructors for each entrypoint. This allows us to satisfy the requirement that LIGO contracts always begin execution from the same function. The main function simply takes this variant, pattern matches it to determine which entrypoint to dispatch the call to, then returns the result of executing that entrypoint with the projected arguments.
|
||||||
|
|
||||||
|
> The LIGO variant's are compiled to a Michelson annotated tree of union type.
|
||||||
|
|
||||||
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
|
<!--Pascaligo-->
|
||||||
|
```pascaligo group=recordentry
|
||||||
|
type parameter_t is
|
||||||
|
| Entrypoint_a of int
|
||||||
|
| Entrypoint_b of string
|
||||||
|
type storage_t is unit
|
||||||
|
type return_t is (list(operation) * storage_t)
|
||||||
|
|
||||||
|
function handle_a (const p : int; const store : storage_t) : return_t is
|
||||||
|
((nil : list(operation)), store)
|
||||||
|
|
||||||
|
function handle_b (const p : string; const store : storage_t) : return_t is
|
||||||
|
((nil : list(operation)), store)
|
||||||
|
|
||||||
|
function main(const parameter: parameter_t; const store: storage_t): return_t is
|
||||||
|
case parameter of
|
||||||
|
| Entrypoint_a (p) -> handle_a(p,store)
|
||||||
|
| Entrypoint_b (p) -> handle_b(p,store)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--CameLIGO-->
|
||||||
|
```cameligo group=recordentry
|
||||||
|
type parameter_t =
|
||||||
|
| Entrypoint_a of int
|
||||||
|
| Entrypoint_b of string
|
||||||
|
type storage_t = unit
|
||||||
|
type return_t = (operation list * storage_t)
|
||||||
|
|
||||||
|
let handle_a (parameter, store: int * storage_t) : return_t =
|
||||||
|
(([]: operation list), store)
|
||||||
|
|
||||||
|
let handle_b (parameter, store: string * storage_t) : return_t =
|
||||||
|
(([]: operation list), store)
|
||||||
|
|
||||||
|
let main (parameter, store: parameter_t * storage_t) : return_t =
|
||||||
|
match parameter with
|
||||||
|
| Entrypoint_a p -> handle_a (p,store)
|
||||||
|
| Entrypoint_b p -> handle_b (p,store)
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--ReasonLIGO-->
|
||||||
|
```reasonligo group=recordentry
|
||||||
|
type parameter_t =
|
||||||
|
| Entrypoint_a(int)
|
||||||
|
| Entrypoint_b(string);
|
||||||
|
type storage_t = unit;
|
||||||
|
type return_t = (list(operation) , storage_t);
|
||||||
|
|
||||||
|
let handle_a = ((parameter, store): (int, storage_t)) : return_t => {
|
||||||
|
(([]: list(operation)), store); };
|
||||||
|
|
||||||
|
let handle_b = ((parameter, store): (string, storage_t)) : return_t => {
|
||||||
|
(([]: list(operation)), store); };
|
||||||
|
|
||||||
|
let main = ((parameter, store): (parameter_t, storage_t)) : return_t => {
|
||||||
|
switch (parameter) {
|
||||||
|
| Entrypoint_a(p) => handle_a((p,store))
|
||||||
|
| Entrypoint_b(p) => handle_b((p,store))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
|
|
||||||
## Built-in contract variables
|
## Built-in contract variables
|
||||||
|
@ -15,10 +15,10 @@ Each `block` needs to include at least one `instruction`, or a *placeholder* ins
|
|||||||
|
|
||||||
```pascaligo skip
|
```pascaligo skip
|
||||||
// shorthand syntax
|
// shorthand syntax
|
||||||
block { skip }
|
block { a := a + 1 }
|
||||||
// verbose syntax
|
// verbose syntax
|
||||||
begin
|
begin
|
||||||
skip
|
a := a + 1
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -29,10 +29,11 @@ end
|
|||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
|
|
||||||
Functions in PascaLIGO are defined using the `function` keyword followed by their `name`, `parameters` and `return` type definitions.
|
Functions in PascaLIGO are defined using the `function` keyword
|
||||||
|
followed by their `name`, `parameters` and `return` type definitions.
|
||||||
Here's how you define a basic function that accepts two `ints` and returns a single `int`:
|
|
||||||
|
|
||||||
|
Here's how you define a basic function that accepts two `int`s and
|
||||||
|
returns a single `int`:
|
||||||
|
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
function add(const a: int; const b: int): int is
|
function add(const a: int; const b: int): int is
|
||||||
@ -48,8 +49,10 @@ The function body consists of two parts:
|
|||||||
|
|
||||||
#### Blockless functions
|
#### Blockless functions
|
||||||
|
|
||||||
Functions that can contain all of their logic into a single instruction/expression, can be defined without the surrounding `block`.
|
Functions that can contain all of their logic into a single
|
||||||
Instead, you can inline the necessary logic directly, like this:
|
instruction/expression, can be defined without the surrounding
|
||||||
|
`block`. Instead, you can inline the necessary logic directly, like
|
||||||
|
this:
|
||||||
|
|
||||||
```pascaligo group=b
|
```pascaligo group=b
|
||||||
function add(const a: int; const b: int): int is a + b
|
function add(const a: int; const b: int): int is a + b
|
||||||
@ -57,72 +60,78 @@ function add(const a: int; const b: int): int is a + b
|
|||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
|
|
||||||
Functions in CameLIGO are defined using the `let` keyword, like value bindings.
|
Functions in CameLIGO are defined using the `let` keyword, like value
|
||||||
The difference is that after the value name a list of function parameters is provided,
|
bindings. The difference is that after the value name a list of
|
||||||
along with a return type.
|
function parameters is provided, along with a return type.
|
||||||
|
|
||||||
CameLIGO is a little different from other syntaxes when it comes to function
|
CameLIGO is a little different from other syntaxes when it comes to
|
||||||
parameters. In OCaml, functions can only take one parameter. To get functions
|
function parameters. In OCaml, functions can only take one
|
||||||
with multiple arguments like we're used to in traditional programming languages,
|
parameter. To get functions with multiple arguments like we are used
|
||||||
a technique called [currying](https://en.wikipedia.org/wiki/Currying) is used.
|
to in traditional programming languages, a technique called
|
||||||
Currying essentially translates a function with multiple arguments into a series
|
[currying](https://en.wikipedia.org/wiki/Currying) is used. Currying
|
||||||
of single argument functions, each returning a new function accepting the next
|
essentially translates a function with multiple arguments into a
|
||||||
argument until every parameter is filled. This is useful because it means that
|
series of single argument functions, each returning a new function
|
||||||
CameLIGO can support [partial application](https://en.wikipedia.org/wiki/Partial_application).
|
accepting the next argument until every parameter is filled. This is
|
||||||
|
useful because it means that CameLIGO can support
|
||||||
|
[partial application](https://en.wikipedia.org/wiki/Partial_application).
|
||||||
|
|
||||||
Currying is however *not* the preferred way to pass function arguments in CameLIGO.
|
Currying is however *not* the preferred way to pass function arguments
|
||||||
While this approach is faithful to the original OCaml, it's costlier in Michelson
|
in CameLIGO. While this approach is faithful to the original OCaml,
|
||||||
than naive function execution accepting multiple arguments. Instead for most
|
it's costlier in Michelson than naive function execution accepting
|
||||||
functions with more than one parameter we should place the arguments in a
|
multiple arguments. Instead for most functions with more than one
|
||||||
[tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as a single
|
parameter we should place the arguments in a
|
||||||
parameter.
|
[tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as
|
||||||
|
a single parameter.
|
||||||
|
|
||||||
Here's how you define a basic function that accepts two `ints` and returns an `int` as well:
|
Here is how you define a basic function that accepts two `ints` and
|
||||||
|
returns an `int` as well:
|
||||||
|
|
||||||
```cameligo group=b
|
```cameligo group=b
|
||||||
|
|
||||||
let add (a,b: int * int) : int = a + b
|
let add (a,b: int * int) : int = a + b
|
||||||
|
|
||||||
let add_curry (a: int) (b: int) : int = a + b
|
let add_curry (a: int) (b: int) : int = a + b
|
||||||
```
|
```
|
||||||
|
|
||||||
The function body is a series of expressions, which are evaluated to give the return
|
The function body is a series of expressions, which are evaluated to
|
||||||
value.
|
give the return value.
|
||||||
|
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
|
|
||||||
Functions in ReasonLIGO are defined using the `let` keyword, like value bindings.
|
Functions in ReasonLIGO are defined using the `let` keyword, like
|
||||||
The difference is that after the value name a list of function parameters is provided,
|
value bindings. The difference is that after the value name a list of
|
||||||
along with a return type.
|
function parameters is provided, along with a return type.
|
||||||
|
|
||||||
Here's how you define a basic function that accepts two `ints` and returns an `int` as well:
|
Here is how you define a basic function that accepts two `int`s and
|
||||||
|
returns an `int` as well:
|
||||||
|
|
||||||
```reasonligo group=b
|
```reasonligo group=b
|
||||||
let add = ((a,b): (int, int)) : int => a + b;
|
let add = ((a,b): (int, int)) : int => a + b;
|
||||||
```
|
```
|
||||||
|
|
||||||
The function body is a series of expressions, which are evaluated to give the return
|
The function body is a series of expressions, which are evaluated to
|
||||||
value.
|
give the return value.
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
## Anonymous functions
|
## Anonymous functions
|
||||||
|
|
||||||
Functions without a name, also known as anonymous functions are useful in cases when you want to pass the function as an argument or assign it to a key in a record/map.
|
Functions without a name, also known as anonymous functions are useful
|
||||||
|
in cases when you want to pass the function as an argument or assign
|
||||||
|
it to a key in a record or a map.
|
||||||
|
|
||||||
Here's how to define an anonymous function assigned to a variable `increment`, with it's appropriate function type signature.
|
Here's how to define an anonymous function assigned to a variable
|
||||||
|
`increment`, with it is appropriate function type signature.
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=c
|
```pascaligo group=c
|
||||||
const increment : (int -> int) = (function (const i : int) : int is i + 1);
|
const increment : int -> int = function (const i : int) : int is i + 1;
|
||||||
// a = 2
|
// a = 2
|
||||||
const a: int = increment (1);
|
const a: int = increment (1);
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
```cameligo group=c
|
```cameligo group=c
|
||||||
let increment : (int -> int) = fun (i: int) -> i + 1
|
let increment : int -> int = fun (i: int) -> i + 1
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
|
@ -3,19 +3,22 @@ id: maps-records
|
|||||||
title: Maps, Records
|
title: Maps, Records
|
||||||
---
|
---
|
||||||
|
|
||||||
So far we've seen pretty basic data types. LIGO also offers more complex built-in constructs, such as Maps and Records.
|
So far we have seen pretty basic data types. LIGO also offers more
|
||||||
|
complex built-in constructs, such as maps and records.
|
||||||
|
|
||||||
## Maps
|
## Maps
|
||||||
|
|
||||||
Maps are natively available in Michelson, and LIGO builds on top of them. A requirement for a Map is that its keys be of the same type, and that type must be comparable.
|
Maps are natively available in Michelson, and LIGO builds on top of
|
||||||
|
them. A requirement for a map is that its keys be of the same type,
|
||||||
|
and that type must be comparable.
|
||||||
|
|
||||||
Here's how a custom map type is defined:
|
Here is how a custom map type is defined:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
type move is (int * int);
|
type move is int * int
|
||||||
type moveset is map(address, move);
|
type moveset is map(address, move)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
@ -32,7 +35,7 @@ type moveset = map(address, move);
|
|||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
And here's how a map value is populated:
|
And here is how a map value is populated:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
@ -77,7 +80,10 @@ let moves : moveset =
|
|||||||
|
|
||||||
### Accessing map values by key
|
### Accessing map values by key
|
||||||
|
|
||||||
If we want to access a move from our moveset above, we can use the `[]` operator/accessor to read the associated `move` value. However, the value we'll get will be wrapped as an optional; in our case `option(move)`. Here's an example:
|
If we want to access a move from our moveset above, we can use the
|
||||||
|
`[]` operator/accessor to read the associated `move` value. However,
|
||||||
|
the value we will get will be wrapped as an optional; in our case
|
||||||
|
`option(move)`. Here is an example:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
@ -175,7 +181,7 @@ otherwise.
|
|||||||
function iter_op (const m : moveset) : unit is
|
function iter_op (const m : moveset) : unit is
|
||||||
block {
|
block {
|
||||||
function aggregate (const i : address ; const j : move) : unit is block
|
function aggregate (const i : address ; const j : move) : unit is block
|
||||||
{ if (j.1 > 1) then skip else failwith("fail") } with unit ;
|
{ if j.1 > 1 then skip else failwith("fail") } with unit
|
||||||
} with map_iter(aggregate, m);
|
} with map_iter(aggregate, m);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -202,7 +208,7 @@ let iter_op = (m: moveset): unit => {
|
|||||||
```pascaligo
|
```pascaligo
|
||||||
function map_op (const m : moveset) : moveset is
|
function map_op (const m : moveset) : moveset is
|
||||||
block {
|
block {
|
||||||
function increment (const i : address ; const j : move) : move is block { skip } with (j.0, j.1 + 1) ;
|
function increment (const i : address ; const j : move) : move is (j.0, j.1 + 1);
|
||||||
} with map_map (increment, m);
|
} with map_map (increment, m);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -222,29 +228,30 @@ let map_op = (m: moveset): moveset => {
|
|||||||
```
|
```
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
`fold` is an aggregation function that return the combination of a maps contents.
|
`fold` is an aggregation function that return the combination of a
|
||||||
|
maps contents.
|
||||||
|
|
||||||
The fold is a loop which extracts an element of the map on each iteration. It then
|
The fold is a loop which extracts an element of the map on each
|
||||||
provides this element and an existing value to a folding function which combines them.
|
iteration. It then provides this element and an existing value to a
|
||||||
On the first iteration, the existing value is an initial expression given by the
|
folding function which combines them. On the first iteration, the
|
||||||
programmer. On each subsequent iteration it is the result of the previous iteration.
|
existing value is an initial expression given by the programmer. On
|
||||||
|
each subsequent iteration it is the result of the previous iteration.
|
||||||
It eventually returns the result of combining all the elements.
|
It eventually returns the result of combining all the elements.
|
||||||
|
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
function fold_op (const m : moveset) : int is
|
function fold_op (const m : moveset) : int is
|
||||||
block {
|
block {
|
||||||
function aggregate (const j : int ; const cur : (address * (int * int))) : int is j + cur.1.1 ;
|
function aggregate (const j : int; const cur : address * (int * int)) : int is j + cur.1.1
|
||||||
} with map_fold(aggregate, m, 5)
|
} with map_fold(aggregate, m, 5)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
```cameligo
|
```cameligo
|
||||||
let fold_op (m : moveset) : moveset =
|
let fold_op (m : moveset) : moveset =
|
||||||
let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1 in
|
let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1
|
||||||
Map.fold aggregate m 5
|
in Map.fold aggregate m 5
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
@ -268,13 +275,13 @@ too expensive were it not for big maps. Big maps are a data structure offered by
|
|||||||
Tezos which handles the scaling concerns for us. In LIGO, the interface for big
|
Tezos which handles the scaling concerns for us. In LIGO, the interface for big
|
||||||
maps is analogous to the one used for ordinary maps.
|
maps is analogous to the one used for ordinary maps.
|
||||||
|
|
||||||
Here's how we define a big map:
|
Here is how we define a big map:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
type move is (int * int);
|
type move is (int * int)
|
||||||
type moveset is big_map(address, move);
|
type moveset is big_map (address, move)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
@ -291,13 +298,14 @@ type moveset = big_map(address, move);
|
|||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
And here's how a map value is populated:
|
And here is how a map value is populated:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
|
|
||||||
```pascaligo
|
```pascaligo
|
||||||
const moves: moveset = big_map
|
const moves: moveset =
|
||||||
|
big_map
|
||||||
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
|
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
|
||||||
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
|
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
|
||||||
end
|
end
|
||||||
@ -309,15 +317,16 @@ end
|
|||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
|
|
||||||
```cameligo
|
```cameligo
|
||||||
let moves: moveset = Big_map.literal
|
let moves: moveset =
|
||||||
[ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1, 2)) ;
|
Big_map.literal [
|
||||||
|
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2));
|
||||||
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
|
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
> Big_map.literal constructs the map from a list of key-value pair tuples, `(<key>, <value>)`.
|
> Big_map.literal constructs the map from a list of key-value pair tuples, `(<key>, <value>)`.
|
||||||
> Note also the `;` to separate individual map entries.
|
> Note also the `;` to separate individual map entries.
|
||||||
>
|
>
|
||||||
> `("<string value>": address)` means that we type-cast a string into an address.
|
> `("<string value>": address)` means that we cast a string into an address.
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
|
|
||||||
@ -330,24 +339,29 @@ let moves: moveset =
|
|||||||
```
|
```
|
||||||
> Big_map.literal constructs the map from a list of key-value pair tuples, `(<key>, <value>)`.
|
> Big_map.literal constructs the map from a list of key-value pair tuples, `(<key>, <value>)`.
|
||||||
>
|
>
|
||||||
> `("<string value>": address)` means that we type-cast a string into an address.
|
> `("<string value>": address)` means that we cast a string into an address.
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
### Accessing map values by key
|
### Accessing map values by key
|
||||||
|
|
||||||
If we want to access a move from our moveset above, we can use the `[]` operator/accessor to read the associated `move` value. However, the value we'll get will be wrapped as an optional; in our case `option(move)`. Here's an example:
|
If we want to access a move from our moveset above, we can use the
|
||||||
|
`[]` operator/accessor to read the associated `move` value. However,
|
||||||
|
the value we will get will be wrapped as an optional; in our case
|
||||||
|
`option(move)`. Here is an example:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
const my_balance : option(move) = moves[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)];
|
const my_balance : option(move) =
|
||||||
|
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)]
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
|
|
||||||
```cameligo
|
```cameligo
|
||||||
let my_balance : move option = Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
|
let my_balance : move option =
|
||||||
|
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
@ -360,24 +374,28 @@ let my_balance : option(move) =
|
|||||||
|
|
||||||
#### Obtaining a map value forcefully
|
#### Obtaining a map value forcefully
|
||||||
|
|
||||||
Accessing a value in a map yields an option, however you can also get the value directly:
|
Accessing a value in a map yields an option, however you can also get
|
||||||
|
the value directly:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
const my_balance : move = get_force(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
|
const my_balance : move =
|
||||||
|
get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
|
|
||||||
```cameligo
|
```cameligo
|
||||||
let my_balance : move = Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
|
let my_balance : move =
|
||||||
|
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--ReasonLIGO-->
|
<!--ReasonLIGO-->
|
||||||
|
|
||||||
```reasonligo
|
```reasonligo
|
||||||
let my_balance : move = Big_map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
|
let my_balance : move =
|
||||||
|
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
@ -388,7 +406,8 @@ let my_balance : move = Big_map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": add
|
|||||||
|
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
|
|
||||||
The values of a PascaLIGO big map can be updated using the ordinary assignment syntax:
|
The values of a PascaLIGO big map can be updated using the ordinary
|
||||||
|
assignment syntax:
|
||||||
|
|
||||||
```pascaligo
|
```pascaligo
|
||||||
|
|
||||||
@ -400,7 +419,8 @@ function set_ (var m : moveset) : moveset is
|
|||||||
|
|
||||||
<!--Cameligo-->
|
<!--Cameligo-->
|
||||||
|
|
||||||
We can update a big map in CameLIGO using the `Big_map.update` built-in:
|
We can update a big map in CameLIGO using the `Big_map.update`
|
||||||
|
built-in:
|
||||||
|
|
||||||
```cameligo
|
```cameligo
|
||||||
|
|
||||||
@ -410,7 +430,8 @@ let updated_map : moveset =
|
|||||||
|
|
||||||
<!--Reasonligo-->
|
<!--Reasonligo-->
|
||||||
|
|
||||||
We can update a big map in ReasonLIGO using the `Big_map.update` built-in:
|
We can update a big map in ReasonLIGO using the `Big_map.update`
|
||||||
|
built-in:
|
||||||
|
|
||||||
```reasonligo
|
```reasonligo
|
||||||
let updated_map : moveset =
|
let updated_map : moveset =
|
||||||
@ -421,17 +442,20 @@ let updated_map: moveset =
|
|||||||
|
|
||||||
## Records
|
## Records
|
||||||
|
|
||||||
Records are a construct introduced in LIGO, and are not natively available in Michelson. The LIGO compiler translates records into Michelson `Pairs`.
|
Records are a construct introduced in LIGO, and are not natively
|
||||||
|
available in Michelson. The LIGO compiler translates records into
|
||||||
|
Michelson `Pairs`.
|
||||||
|
|
||||||
Here's how a custom record type is defined:
|
Here is how a custom record type is defined:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
type user is record
|
type user is
|
||||||
|
record
|
||||||
id : nat;
|
id : nat;
|
||||||
is_admin : bool;
|
is_admin : bool;
|
||||||
name: string;
|
name : string
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -440,7 +464,7 @@ end
|
|||||||
type user = {
|
type user = {
|
||||||
id : nat;
|
id : nat;
|
||||||
is_admin : bool;
|
is_admin : bool;
|
||||||
name: string;
|
name : string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -455,15 +479,16 @@ type user = {
|
|||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
And here's how a record value is populated:
|
And here is how a record value is populated:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo
|
```pascaligo
|
||||||
const user: user = record
|
const user : user =
|
||||||
|
record
|
||||||
id = 1n;
|
id = 1n;
|
||||||
is_admin = True;
|
is_admin = True;
|
||||||
name = "Alice";
|
name = "Alice"
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -472,7 +497,7 @@ end
|
|||||||
let user : user = {
|
let user : user = {
|
||||||
id = 1n;
|
id = 1n;
|
||||||
is_admin = true;
|
is_admin = true;
|
||||||
name = "Alice";
|
name = "Alice"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -486,10 +511,10 @@ let user: user = {
|
|||||||
```
|
```
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
|
||||||
|
|
||||||
### Accessing record keys by name
|
### Accessing record keys by name
|
||||||
|
|
||||||
If we want to obtain a value from a record for a given key, we can do the following:
|
If we want to obtain a value from a record for a given key, we can do
|
||||||
|
the following:
|
||||||
|
|
||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
@ -506,5 +531,4 @@ let is_admin : bool = user.is_admin
|
|||||||
```reasonligo
|
```reasonligo
|
||||||
let is_admin: bool = user.is_admin;
|
let is_admin: bool = user.is_admin;
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||||
|
@ -3,13 +3,15 @@ id: sets-lists-tuples
|
|||||||
title: Sets, Lists, Tuples
|
title: Sets, Lists, Tuples
|
||||||
---
|
---
|
||||||
|
|
||||||
Apart from complex data types such as `maps` and `records`, ligo also exposes `sets`, `lists` and `tuples`.
|
Apart from complex data types such as `maps` and `records`, ligo also
|
||||||
|
exposes `sets`, `lists` and `tuples`.
|
||||||
|
|
||||||
> ⚠️ Make sure to pick the appropriate data type for your use case; it carries not only semantic but also gas related costs.
|
> ⚠️ Make sure to pick the appropriate data type for your use case; it carries not only semantic but also gas related costs.
|
||||||
|
|
||||||
## Sets
|
## Sets
|
||||||
|
|
||||||
Sets are similar to lists. The main difference is that elements of a `set` must be *unique*.
|
Sets are similar to lists. The main difference is that elements of a
|
||||||
|
`set` must be *unique*.
|
||||||
|
|
||||||
### Defining a set
|
### Defining a set
|
||||||
|
|
||||||
@ -17,11 +19,7 @@ Sets are similar to lists. The main difference is that elements of a `set` must
|
|||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
type int_set is set (int);
|
type int_set is set (int);
|
||||||
const my_set: int_set = set
|
const my_set : int_set = set 1; 2; 3 end
|
||||||
1;
|
|
||||||
2;
|
|
||||||
3;
|
|
||||||
end
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
@ -45,8 +43,8 @@ let my_set: int_set =
|
|||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
const my_set: int_set = set end;
|
const my_set: int_set = set end
|
||||||
const my_set_2: int_set = set_empty;
|
const my_set_2: int_set = set_empty
|
||||||
```
|
```
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
```cameligo group=a
|
```cameligo group=a
|
||||||
@ -63,7 +61,7 @@ let my_set: int_set = (Set.empty: set(int));
|
|||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
const contains_three: bool = my_set contains 3;
|
const contains_three : bool = my_set contains 3
|
||||||
// or alternatively
|
// or alternatively
|
||||||
const contains_three_fn: bool = set_mem (3, my_set);
|
const contains_three_fn: bool = set_mem (3, my_set);
|
||||||
```
|
```
|
||||||
@ -84,7 +82,7 @@ let contains_three: bool = Set.mem(3, my_set);
|
|||||||
<!--DOCUSAURUS_CODE_TABS-->
|
<!--DOCUSAURUS_CODE_TABS-->
|
||||||
<!--Pascaligo-->
|
<!--Pascaligo-->
|
||||||
```pascaligo group=a
|
```pascaligo group=a
|
||||||
const set_size: nat = size(my_set);
|
const set_size: nat = size (my_set)
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--CameLIGO-->
|
<!--CameLIGO-->
|
||||||
|
Loading…
Reference in New Issue
Block a user