From 127a85822ff32aa2a2e2aef666b8edb6d3375f9c Mon Sep 17 00:00:00 2001 From: Christian Rinderknecht Date: Wed, 26 Feb 2020 18:31:58 +0100 Subject: [PATCH] More updates to the documentation. Synced the new reference page. --- .../docs/language-basics/maps-records.md | 14 +- .../docs/language-basics/math-numbers-tez.md | 43 +- .../docs/language-basics/sets-lists-tuples.md | 24 +- gitlab-pages/docs/reference/big_map.md | 193 +++------ gitlab-pages/docs/reference/current.md | 256 +++++++----- gitlab-pages/docs/reference/list.md | 144 ++----- gitlab-pages/docs/reference/map.md | 371 +++++++++++------- gitlab-pages/docs/reference/set.md | 329 ++++++++-------- 8 files changed, 694 insertions(+), 680 deletions(-) diff --git a/gitlab-pages/docs/language-basics/maps-records.md b/gitlab-pages/docs/language-basics/maps-records.md index f1b491b60..c9837fb26 100644 --- a/gitlab-pages/docs/language-basics/maps-records.md +++ b/gitlab-pages/docs/language-basics/maps-records.md @@ -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*. @@ -733,21 +732,18 @@ Here is how we define a big map: ```pascaligo group=big_maps type move is int * int - type register is big_map (address, move) ``` ```cameligo group=big_maps type move = int * int - type register = (address, move) big_map ``` ```reasonligo group=big_maps type move = (int, int); - type register = big_map (address, move); ``` @@ -789,10 +785,10 @@ 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 --> - `("" : address)` means that we cast a string into an --> - address. --> +Notice the right arrow `->` between the key and its value and the +semicolon separating individual map entries. The value annotation +`("" : address)` means that we cast a string into an +address. --> diff --git a/gitlab-pages/docs/language-basics/math-numbers-tez.md b/gitlab-pages/docs/language-basics/math-numbers-tez.md index 7d8c2342a..31bdeb872 100644 --- a/gitlab-pages/docs/language-basics/math-numbers-tez.md +++ b/gitlab-pages/docs/language-basics/math-numbers-tez.md @@ -213,7 +213,7 @@ let c : tez = 5n * 5mutez; -## Division +## Euclidean Division In LIGO you can divide `int`, `nat`, and `tez`. Here is how: @@ -243,6 +243,46 @@ let c : nat = 10mutez / 3mutez; +LIGO also allows you to compute the remainder of the Euclidean +division. In LIGO, it is a natural number. + + + +```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 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 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); ``` - ## Checking a `nat` diff --git a/gitlab-pages/docs/language-basics/sets-lists-tuples.md b/gitlab-pages/docs/language-basics/sets-lists-tuples.md index abf8b4b20..8bcb192f6 100644 --- a/gitlab-pages/docs/language-basics/sets-lists-tuples.md +++ b/gitlab-pages/docs/language-basics/sets-lists-tuples.md @@ -124,7 +124,6 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1 - ### 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 group=sets @@ -636,12 +639,9 @@ traversal of the data structure is over. The predefined fold over sets is called `Set.fold`. - - ```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 group=sets let sum (acc, i : int * int) : int = acc + i - let sum_of_elements : 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); ``` diff --git a/gitlab-pages/docs/reference/big_map.md b/gitlab-pages/docs/reference/big_map.md index fa0fa3ebc..57f222dc0 100644 --- a/gitlab-pages/docs/reference/big_map.md +++ b/gitlab-pages/docs/reference/big_map.md @@ -1,137 +1,117 @@ --- 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 - -```pascaligo group=big_map + +```pascaligo group=big_maps type move is int * int type register is big_map (address, move) ``` -```cameligo group=big_map +```cameligo group=big_maps type move = int * int type register = (address, move) big_map ``` -```reasonligo group=big_map +```reasonligo group=big_maps type move = (int, int); type register = big_map (address, move); ``` - -## Creating an Empty Big Map -Create an empty big map. +# Creating an Empty Big Map -```pascaligo group=big_map +```pascaligo group=big_maps const empty : register = big_map [] ``` -```cameligo group=big_map +```cameligo group=big_maps let empty : register = Big_map.empty ``` -```reasonligo group=big_map +```reasonligo group=big_maps let empty : register = Big_map.empty ``` - -## Populating A Big Map +# Creating a Non-empty Map - -```pascaligo group=big_map -const moves: register = + +```pascaligo group=big_maps +const moves : register = big_map [ ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2); ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)] ``` - -```cameligo group=big_map -let moves: register = +```cameligo group=big_maps +let moves : register = Big_map.literal [ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2)); (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))] ``` - -```reasonligo group=big_map -let moves: register = +```reasonligo group=big_maps +let moves : register = Big_map.literal ([ ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)), ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]); ``` - -## 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 - -```pascaligo group=big_map + +```pascaligo group=big_maps const my_balance : option (move) = moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)] ``` - -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 ``` - -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); ``` -## 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 - - - -The values of a PascaLIGO big map can be updated using the ordinary -assignment syntax: - -```pascaligo group=big_map + +```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. - - - -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 group=big_maps let updated_map : register = Big_map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves ``` - - -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 group=big_maps let updated_map : register = Big_map.update (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves); ``` - -## Adding a Binding to a Big Map - -Add a key and its associated value to the big map. - - - -```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) -``` - - - -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 -``` - - - -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); -``` - - - -## Removing a Binding from a Big Map - -Remove a key and its associated value from the big map. +# Removing Bindings -```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) ``` - -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 ``` - -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) ``` diff --git a/gitlab-pages/docs/reference/current.md b/gitlab-pages/docs/reference/current.md index c9f1945d8..53fec4d7d 100644 --- a/gitlab-pages/docs/reference/current.md +++ b/gitlab-pages/docs/reference/current.md @@ -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. @@ -11,26 +11,36 @@ Get the balance for the contract. ```pascaligo -function main (const p : unit; const s: tez) : list(operation) * tez is - ((nil : list(operation)), balance) +function main (const p : unit; const s: tez) : list (operation) * tez is + ((nil : list (operation)), Tezos.balance) ``` + +> Note that `balance` and `Current.balance` are *deprecated*. + ```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 -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*. + -## Current.time() : timestamp +## Tezos.now -Returns the current time as a [unix timestamp](https://en.wikipedia.org/wiki/Unix_time). +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 ```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 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 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*. + #### 24 hours ago + ```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 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 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*. + -#### 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 ```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 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 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*. + -## 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. ```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 -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 -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*. + -## 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 -function main (const p: unit) : address is sender +function main (const p : unit) : address is Tezos.sender ``` +> Note that `sender` is *deprecated*. + ```cameligo -let main (p: unit) : address = Current.sender +let main (p: unit) : address = Tezos.sender ``` +> Note that `Current.sender` is *deprecated*. + ```reasonligo -let main = (p: unit) : address => Current.sender; +let main = (p : unit) : address => Tezos.sender; ``` +> Note that `Current.sender` is *deprecated*. + -## Current.address(c: a' contract) : address -Get the address associated with a `contract`. +## Address + +Get the address associated with a value of type `contract`. ```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 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 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*. + -## Current.self_address() : address +## Self Address Get the address of the currently running contract. @@ -210,110 +251,137 @@ Get the address of the currently running contract. ```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 -let main (p: unit) : address = Current.self_address +let main (p : unit) : address = Tezos.self_address ``` +> Note that `Current.self_address` is *deprecated*. + ```reasonligo -let main = (p: unit): address => Current.self_address; +let main = (p : unit) : address => Tezos.self_address; ``` +> Note that `Current.self_address` is *deprecated*. + -## 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. ```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 -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 -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*. + -## 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. ```pascaligo -function main (const p: unit) : address is source +function main (const p: unit) : address is Tezos.source ``` +> Note that `source` is *deprecated*. + ```cameligo -let main (p: unit) : address = Current.source +let main (p : unit) : address = Tezos.source ``` +> Note that `Current.source` is *deprecated*. + ```reasonligo -let main = (p: unit) : address => Current.source; +let main = (p : unit) : address => Tezos.source; ``` +> Note that `Current.source` is *deprecated*. -## 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. ```pascaligo -function main (const p : int; const s : unit) : list(operation) * unit is +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) + with ((nil : list (operation)), s) ``` ```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 -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."); }; ``` diff --git a/gitlab-pages/docs/reference/list.md b/gitlab-pages/docs/reference/list.md index 1c34215fe..96d733d50 100644 --- a/gitlab-pages/docs/reference/list.md +++ b/gitlab-pages/docs/reference/list.md @@ -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 @@ -34,7 +34,7 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1 -### 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] -### 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 group=lists @@ -108,7 +112,7 @@ let iter_op = (l : list (int)) : unit => { -#### 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 group=lists @@ -144,7 +150,8 @@ let plus_one : list (int) = List.map (increment, larger_list); ``` -#### 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 group=lists @@ -176,7 +185,7 @@ let sum_of_elements : int = List.fold (sum, my_list, 0); ``` -## 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 let size_of (l : int list) : nat = List.length l @@ -198,112 +209,3 @@ let size_of = (l : list (int)) : nat => List.length (l); ``` - -## 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. - - - -```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 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 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]); -``` - - - -## 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. - - - - -```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 -let iter_op (s : int list) : unit = - let do_nothing = fun (_: int) -> unit - in List.iter do_nothing s -``` - - -```reasonligo -let iter_op = (s: list(int)): unit => { - let do_nothing = (z: int) => unit; - List.iter(do_nothing, s); -}; -``` - - - -## 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. - - - -```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 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 group=b -let sum = ((result, i): (int, int)): int => result + i; -let sum_of_a_list: int = List.fold(sum, [1, 2, 3], 0); -``` - - diff --git a/gitlab-pages/docs/reference/map.md b/gitlab-pages/docs/reference/map.md index c7a5590e7..df3ecbb31 100644 --- a/gitlab-pages/docs/reference/map.md +++ b/gitlab-pages/docs/reference/map.md @@ -1,211 +1,199 @@ --- 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 - -```pascaligo group=map + + +```pascaligo group=maps type move is int * int type register is map (address, move) ``` -```cameligo group=map +```cameligo group=maps type move = int * int type register = (address, move) map ``` -```reasonligo group=map +```reasonligo group=maps type move = (int, int); type register = map (address, move); ``` - -## Creating an Empty Map - -Create an empty map. +# Creating an Empty Map -```pascaligo group=map +```pascaligo group=maps const empty : register = map [] ``` -```cameligo group=map +```cameligo group=maps let empty : register = Map.empty ``` -```reasonligo group=map +```reasonligo group=maps let empty : register = Map.empty ``` - -## Populating A Map +# Creating a Non-empty Map - - -```pascaligo group=map -const moves: register = + +```pascaligo group=maps +const moves : register = map [ ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2); ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)] ``` - -```cameligo group=map -let moves: register = +```cameligo group=maps +let moves : register = Map.literal [ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2)); (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))] ``` - -```reasonligo group=map -let moves: register = +```reasonligo group=maps +let moves : register = Map.literal ([ ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)), ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]); ``` - -## 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 - -```pascaligo group=map + +```pascaligo group=maps const my_balance : option (move) = moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)] ``` - -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 ``` - -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); ``` -## 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*. - - -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. - - - -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 -``` - - - -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); -``` - - - -## Adding a Binding to a Map - -Add a key and its associated value to the map. - - - -```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 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 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 group=maps +let force_access = ((key, moves) : (address, register)) : move => { + switch (Map.find_opt (key, moves)) { + | Some (move) => move + | None => failwith ("No move.") : move + } +}; +``` + -```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*. + + + +```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 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 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 => -## 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. -```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 ``` - -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 ``` - -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); ``` -## 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. -```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 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 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); +}; +``` + + +## 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`. + + + + + +```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 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 group=maps +let map_op = (m : register) : register => { + let increment = ((i,j): (address, move)) => (j[0], j[1] + 1); + Map.map (increment, m); +}; +``` + + +## 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. + + + + + +```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 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 group=maps +let fold_op = (m : register) : register => { + let folded = ((i,j): (int, (address, move))) => i + j[1][1]; + Map.fold (folded, m, 5); +}; ``` diff --git a/gitlab-pages/docs/reference/set.md b/gitlab-pages/docs/reference/set.md index 08c7be4f3..c989df627 100644 --- a/gitlab-pages/docs/reference/set.md +++ b/gitlab-pages/docs/reference/set.md @@ -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 - -```pascaligo group=a -type int_set is set (int); -const my_set : int_set = set 1; 2; 3 end + +```pascaligo group=sets +const my_set : set (int) = set [] ``` -```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 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; ``` - - -## Set.mem(is_member: a', s: a' set) : bool - -Check if a set `s` contains the element `is_member`. +# Non-empty Sets - -```pascaligo group=a -const contains_three : bool = my_set contains 3 -// or alternatively -const contains_three_fn: bool = set_mem (3, my_set); + +```pascaligo group=sets +const my_set : set (int) = set [3; 2; 2; 1] ``` -```cameligo group=a -let contains_three: bool = Set.mem 3 my_set -``` - -```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 group=sets +let my_set : set (int) = + Set.add (3, Set.add (2, Set.add (2, Set.add (1, Set.empty : set (int))))); +``` - -## Set.empty() : a' set - -Create a new empty set. Needs to be annotated with the set type. +# Set Membership - -```pascaligo group=a -const my_set: int_set = set end -const my_set_2: int_set = set_empty + +```pascaligo group=sets +const contains_3 : bool = my_set contains 3 ``` + -```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 group=a -let my_set: int_set = (Set.empty: set (int)); +```reasonligo group=sets +let contains_3 : bool = Set.mem (3, my_set); ``` -## 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. + + + +```pascaligo group=sets +const cardinal : nat = Set.size (my_set) +``` + +> Note that `size` is *deprecated*. + + +```cameligo group=sets +let cardinal : nat = Set.size my_set +``` + +```reasonligo group=sets +let cardinal : nat = Set.size (my_set); +``` + + +# Updating Sets + +There are two ways to update a set, that is to add or remove from it. + + + +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 group=sets +let larger_set : int set = Set.add 4 my_set +let smaller_set : int set = Set.remove 3 my_set +``` + + +```reasonligo group=sets +let larger_set : set (int) = Set.add (4, my_set); +let smaller_set : set (int) = Set.remove (3, my_set); +``` + + +# 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. + + + +```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 group=sets +let iter_op (s : int set) : unit = + let predicate = fun (i : int) -> assert (i > 3) + in Set.iter predicate s +``` + + +```reasonligo group=sets +let iter_op = (s : set (int)) : unit => { + let predicate = (i : int) => assert (i > 3); + Set.iter (predicate, s); +}; +``` + + +## 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. -```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 -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 -let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]); -``` - - - -## Set.add(addition: a', s: a' set) : a' set - -Add the element `addition` to a set `s`. - - - -```pascaligo group=a -function add_op (const s : set(string)) : set(string) is - begin skip end with set_add("foobar" , s) -``` - - -```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 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)))); -``` - - - -## Set.remove(removal: a', s: a' set) : a' set - -Remove the element `removal` from a set `s`. - - - -```pascaligo group=a -const smaller_set: int_set = set_remove(3, my_set); -``` - - - -```cameligo group=a -let smaller_set: int_set = Set.remove 3 my_set -``` - - - -```reasonligo group=a -let smaller_set: int_set = Set.remove(3, my_set); -``` - - - - -## 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. - - - -```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 group=a -let sum (result, i: int * int) : int = result + i -let sum_of_a_set: int = Set.fold sum my_set 0 -``` - - -```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); ``` - -## Set.size(s: a' set) : nat - -Get the number of elements in a set. - - - -```pascaligo group=a -const set_size: nat = size (my_set) -``` - - -```cameligo group=a -let set_size: nat = Set.size my_set -``` - - -```reasonligo group=a -let set_size: nat = Set.size (my_set); -``` - -