From 149242a3711fef3fdb7d70ddb5d40871147579f2 Mon Sep 17 00:00:00 2001 From: Christian Rinderknecht Date: Tue, 28 Jan 2020 15:13:50 +0100 Subject: [PATCH] Updates. --- .../docs/language-basics/functions.md | 97 +++++----- .../docs/language-basics/maps-records.md | 180 ++++++++++-------- .../docs/language-basics/sets-lists-tuples.md | 36 ++-- 3 files changed, 172 insertions(+), 141 deletions(-) diff --git a/gitlab-pages/docs/language-basics/functions.md b/gitlab-pages/docs/language-basics/functions.md index 5cf99f761..b8a839817 100644 --- a/gitlab-pages/docs/language-basics/functions.md +++ b/gitlab-pages/docs/language-basics/functions.md @@ -15,10 +15,10 @@ Each `block` needs to include at least one `instruction`, or a *placeholder* ins ```pascaligo skip // shorthand syntax -block { skip } +block { a := a + 1 } // verbose syntax begin - skip + a := a + 1 end ``` @@ -29,16 +29,17 @@ end -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`: +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 `int`s and +returns a single `int`: ```pascaligo group=a -function add(const a: int; const b: int): int is - begin - const result: int = a + b; - end with result; +function add(const a: int; const b: int): int is + begin + const result: int = a + b; + end with result; ``` The function body consists of two parts: @@ -48,8 +49,10 @@ The function body consists of two parts: #### Blockless functions -Functions that can contain all of their logic into a single instruction/expression, can be defined without the surrounding `block`. -Instead, you can inline the necessary logic directly, like this: +Functions that can contain all of their logic into a single +instruction/expression, can be defined without the surrounding +`block`. Instead, you can inline the necessary logic directly, like +this: ```pascaligo group=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 -Functions in CameLIGO are defined using the `let` keyword, like value bindings. -The difference is that after the value name a list of function parameters is provided, -along with a return type. +Functions in CameLIGO are defined using the `let` keyword, like value +bindings. The difference is that after the value name a list of +function parameters is provided, along with a return type. -CameLIGO is a little different from other syntaxes when it comes to function -parameters. In OCaml, functions can only take one parameter. To get functions -with multiple arguments like we're used to in traditional programming languages, -a technique called [currying](https://en.wikipedia.org/wiki/Currying) is used. -Currying essentially translates a function with multiple arguments into a series -of single argument functions, each returning a new function accepting the next -argument until every parameter is filled. This is useful because it means that -CameLIGO can support [partial application](https://en.wikipedia.org/wiki/Partial_application). +CameLIGO is a little different from other syntaxes when it comes to +function parameters. In OCaml, functions can only take one +parameter. To get functions with multiple arguments like we are used +to in traditional programming languages, a technique called +[currying](https://en.wikipedia.org/wiki/Currying) is used. Currying +essentially translates a function with multiple arguments into a +series of single argument functions, each returning a new function +accepting the next argument until every parameter is filled. This is +useful because it means that CameLIGO can support +[partial application](https://en.wikipedia.org/wiki/Partial_application). -Currying is however *not* the preferred way to pass function arguments in CameLIGO. -While this approach is faithful to the original OCaml, it's costlier in Michelson -than naive function execution accepting multiple arguments. Instead for most -functions with more than one parameter we should place the arguments in a -[tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as a single -parameter. +Currying is however *not* the preferred way to pass function arguments +in CameLIGO. While this approach is faithful to the original OCaml, +it's costlier in Michelson than naive function execution accepting +multiple arguments. Instead for most functions with more than one +parameter we should place the arguments in a +[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 - let add (a,b: int * 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 -value. - +The function body is a series of expressions, which are evaluated to +give the return value. -Functions in ReasonLIGO are defined using the `let` keyword, like value bindings. -The difference is that after the value name a list of function parameters is provided, -along with a return type. +Functions in ReasonLIGO are defined using the `let` keyword, like +value bindings. The difference is that after the value name a list of +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 let add = ((a,b): (int, int)) : int => a + b; ``` -The function body is a series of expressions, which are evaluated to give the return -value. +The function body is a series of expressions, which are evaluated to +give the return value. ## 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. ```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 -const a: int = increment(1); +const a: int = increment (1); ``` ```cameligo group=c -let increment : (int -> int) = fun (i: int) -> i + 1 +let increment : int -> int = fun (i: int) -> i + 1 ``` diff --git a/gitlab-pages/docs/language-basics/maps-records.md b/gitlab-pages/docs/language-basics/maps-records.md index 5f51de96c..3d05d41da 100644 --- a/gitlab-pages/docs/language-basics/maps-records.md +++ b/gitlab-pages/docs/language-basics/maps-records.md @@ -3,19 +3,22 @@ id: 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 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: ```pascaligo -type move is (int * int); -type moveset is map(address, move); +type move is int * int +type moveset is map(address, move) ``` @@ -32,7 +35,7 @@ type moveset = map(address, move); -And here's how a map value is populated: +And here is how a map value is populated: @@ -77,7 +80,10 @@ let moves : moveset = ### 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: @@ -175,8 +181,8 @@ otherwise. function iter_op (const m : moveset) : 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 ; - } with map_iter(aggregate, m) ; + { if j.1 > 1 then skip else failwith("fail") } with unit + } with map_iter(aggregate, m); ``` @@ -189,7 +195,7 @@ let iter_op (m : moveset) : unit = ```reasonligo let iter_op = (m: moveset): unit => { - let assert_eq = ((i,j): (address, move)) => assert(j[0] > 1); + let assert_eq = ((i,j): (address, move)) => assert (j[0] > 1); Map.iter(assert_eq, m); }; ``` @@ -202,8 +208,8 @@ let iter_op = (m: moveset): unit => { ```pascaligo function map_op (const m : moveset) : moveset is block { - function increment (const i : address ; const j : move) : move is block { skip } with (j.0, j.1 + 1) ; - } with map_map(increment, m) ; + function increment (const i : address ; const j : move) : move is (j.0, j.1 + 1); + } with map_map (increment, m); ``` @@ -222,29 +228,30 @@ let map_op = (m: moveset): moveset => { ``` -`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 -provides this element and an existing value to a folding function which combines them. -On the first iteration, the existing value is an initial expression given by the -programmer. On each subsequent iteration it is the result of the previous iteration. +The fold is a loop which extracts an element of the map on each +iteration. It then provides this element and an existing value to a +folding function which combines them. On the first iteration, the +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. - ```pascaligo function fold_op (const m : moveset) : int is block { - function aggregate (const j : int ; const cur : (address * (int * int))) : int is j + cur.1.1 ; - } with map_fold(aggregate, m , 5) + function aggregate (const j : int; const cur : address * (int * int)) : int is j + cur.1.1 + } with map_fold(aggregate, m, 5) ``` ```cameligo let fold_op (m : moveset) : moveset = - let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1 in - Map.fold aggregate m 5 + let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1 + in Map.fold aggregate m 5 ``` @@ -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 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: ```pascaligo -type move is (int * int); -type moveset is big_map(address, move); +type move is (int * int) +type moveset is big_map (address, move) ``` @@ -291,16 +298,17 @@ type moveset = big_map(address, move); -And here's how a map value is populated: +And here is how a map value is populated: ```pascaligo -const moves: moveset = big_map - ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1, 2); - ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0, 3); -end +const moves: moveset = + big_map + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2); + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3); + end ``` > Notice the `->` between the key and its value and `;` to separate individual map entries. > @@ -309,45 +317,51 @@ end ```cameligo -let moves: moveset = Big_map.literal - [ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1, 2)) ; - (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0, 3)) ; +let moves: moveset = + Big_map.literal [ + (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2)); + (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3)); ] ``` > Big_map.literal constructs the map from a list of key-value pair tuples, `(, )`. > Note also the `;` to separate individual map entries. > -> `("": address)` means that we type-cast a string into an address. +> `("": address)` means that we cast a string into an address. ```reasonligo let moves: moveset = - Big_map.literal([ - ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1, 2)), - ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0, 3)), + Big_map.literal ([ + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)), + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)), ]); ``` > Big_map.literal constructs the map from a list of key-value pair tuples, `(, )`. > -> `("": address)` means that we type-cast a string into an address. +> `("": address)` means that we cast a string into an address. ### 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: ```pascaligo -const my_balance : option(move) = moves[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)]; +const my_balance : option(move) = + moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] ``` ```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 ``` @@ -360,24 +374,28 @@ let my_balance : option(move) = #### 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: ```pascaligo -const my_balance : move = get_force(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves); +const my_balance : move = + get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves); ``` ```cameligo -let my_balance : move = Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves +let my_balance : move = + Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves ``` ```reasonligo -let my_balance : move = Big_map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); +let my_balance : move = + Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); ``` @@ -388,19 +406,21 @@ let my_balance : move = Big_map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": add -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 function set_ (var m : moveset) : moveset is block { - m[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9); + m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9); } with m ``` -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 @@ -410,10 +430,11 @@ let updated_map : moveset = -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 -let updated_map: moveset = +let updated_map : moveset = Big_map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves); ``` @@ -421,75 +442,79 @@ let updated_map: moveset = ## 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: ```pascaligo -type user is record - id: nat; - is_admin: bool; - name: string; -end +type user is + record + id : nat; + is_admin : bool; + name : string + end ``` ```cameligo type user = { - id: nat; - is_admin: bool; - name: string; + id : nat; + is_admin : bool; + name : string } ``` ```reasonligo type user = { - id: nat, - is_admin: bool, - name: string + id : nat, + is_admin : bool, + name : string }; ``` -And here's how a record value is populated: +And here is how a record value is populated: ```pascaligo -const user: user = record - id = 1n; +const user : user = + record + id = 1n; is_admin = True; - name = "Alice"; -end + name = "Alice" + end ``` ```cameligo -let user: user = { - id = 1n; +let user : user = { + id = 1n; is_admin = true; - name = "Alice"; + name = "Alice" } ``` ```reasonligo -let user: user = { - id: 1n, - is_admin: true, - name: "Alice" +let user : user = { + id : 1n, + is_admin : true, + name : "Alice" }; ``` - ### 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: @@ -506,5 +531,4 @@ let is_admin : bool = user.is_admin ```reasonligo let is_admin: bool = user.is_admin; ``` - diff --git a/gitlab-pages/docs/language-basics/sets-lists-tuples.md b/gitlab-pages/docs/language-basics/sets-lists-tuples.md index f423caf7d..bc05f0ce3 100644 --- a/gitlab-pages/docs/language-basics/sets-lists-tuples.md +++ b/gitlab-pages/docs/language-basics/sets-lists-tuples.md @@ -3,39 +3,37 @@ id: 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. ## 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 ```pascaligo group=a -type int_set is set(int); -const my_set: int_set = set - 1; - 2; - 3; -end +type int_set is set (int); +const my_set : int_set = set 1; 2; 3 end ``` ```cameligo group=a type int_set = int set -let my_set: int_set = +let my_set : int_set = Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set))) ``` ```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)))); +type int_set = set (int); +let my_set : int_set = + Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int)))); ``` @@ -45,8 +43,8 @@ let my_set: int_set = ```pascaligo group=a -const my_set: int_set = set end; -const my_set_2: int_set = set_empty; +const my_set: int_set = set end +const my_set_2: int_set = set_empty ``` ```cameligo group=a @@ -54,7 +52,7 @@ let my_set: int_set = (Set.empty: int set) ``` ```reasonligo group=a -let my_set: int_set = (Set.empty: set(int)); +let my_set: int_set = (Set.empty: set (int)); ``` @@ -63,9 +61,9 @@ let my_set: int_set = (Set.empty: set(int)); ```pascaligo group=a -const contains_three: bool = my_set contains 3; +const contains_three : bool = my_set contains 3 // 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); ```pascaligo group=a -const set_size: nat = size(my_set); +const set_size: nat = size (my_set) ``` @@ -94,7 +92,7 @@ let set_size: nat = Set.size my_set ```reasonligo group=a -let set_size: nat = Set.size(my_set); +let set_size: nat = Set.size (my_set); ```