Merge branch 'dev' into docs/map-reference

This commit is contained in:
John David Pressman 2020-02-11 17:56:21 -08:00
commit f2b3e83986
51 changed files with 1125 additions and 434 deletions

View File

@ -2,6 +2,10 @@
## [Unreleased] ## [Unreleased]
## [9164206ef1fcf3e577820442b5afbad92d03ffa4] - 2020-02-09
### Changed
- Mutation of variables inside lambdas passed to list_iter do not have effect anymore. Side-effects used to survive iterations of list_iter via a quirk in the Michelson list_iter. Now, either use a list_fold and explicitly pass through the updated variables (e.g. storage) to the next iteration, or use a `for` loop which automatically detects mutations within the loop body and lifts the affected variables to a record that is passed from iteration to iteration.
## [Add crypto reference page to docs](https://gitlab.com/ligolang/ligo/-/merge_requests/370) ## [Add crypto reference page to docs](https://gitlab.com/ligolang/ligo/-/merge_requests/370)
### Changed ### Changed
- Corrected typo in CameLIGO/ReasonLIGO front end where Crypto.blake2b was 'Crypto.black2b' - Corrected typo in CameLIGO/ReasonLIGO front end where Crypto.blake2b was 'Crypto.black2b'

View File

@ -29,7 +29,7 @@ RUN opam update
# Install ligo # Install ligo
RUN sh scripts/install_vendors_deps.sh RUN sh scripts/install_vendors_deps.sh
RUN opam install -y . || (tail -n +1 ~/.opam/log/* ; false) RUN opam install -y .
# Use the ligo binary as a default command # Use the ligo binary as a default command
ENTRYPOINT [ "/home/opam/.opam/4.07/bin/ligo" ] ENTRYPOINT [ "/home/opam/.opam/4.07/bin/ligo" ]

View File

@ -18,9 +18,9 @@ is provided, but the type of an access function contains both.
The type of the contract parameter and the storage are up to the The type of the contract parameter and the storage are up to the
contract designer, but the type for list operations is not. The return contract designer, but the type for list operations is not. The return
type of an entrypoint is as follows, assuming that the type `storage` type of an access function is as follows, assuming that the type
has been defined elsewhere. (Note that you can use any type with any `storage` has been defined elsewhere. (Note that you can use any type
name for the storage.) with any name for the storage.)
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
@ -45,9 +45,10 @@ type return = (list (operation), storage);
The contract storage can only be modified by activating an access The contract storage can only be modified by activating an access
function. It is important to understand what that means. What it does function. It is important to understand what that means. What it does
*not* mean is that some global variable holding the storage is *not* mean is that some global variable holding the storage is
modified by the entrypoint. Instead, what it *does* mean is that, modified by the access function. Instead, what it *does* mean is that,
given the state of the storage *on-chain*, an entrypoint specifies how given the state of the storage *on-chain*, an access function
to create another state for it, depending on a parameter. specifies how to create another state for it, depending on a
parameter.
Here is an example where the storage is a single natural number that Here is an example where the storage is a single natural number that
is updated by the parameter. is updated by the parameter.
@ -57,28 +58,32 @@ is updated by the parameter.
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo group=a ```pascaligo group=a
type parameter is nat
type storage is nat type storage is nat
type return is list (operation) * storage type return is list (operation) * storage
function save (const parameter : nat; const store : storage) : return is function save (const action : parameter; const store : storage) : return is
((nil : list (operation)), parameter) ((nil : list (operation)), store)
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=a ```cameligo group=a
type parameter = nat
type storage = nat type storage = nat
type return = operation list * storage
let save (parameter, store: nat * storage) : return = let save (action, store: parameter * storage) : return =
(([] : operation list), parameter) (([] : operation list), store)
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=a ```reasonligo group=a
type parameter = nat;
type storage = nat; type storage = nat;
type return = (list (operation), storage);
let main = ((parameter, store): (nat, storage)) : return => { let main = ((action, store): (parameter, storage)) : return =>
(([] : list (operation)), parameter); (([] : list (operation)), store);
};
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
@ -107,8 +112,8 @@ contract, either the counter or the name is updated.
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo group=b ```pascaligo group=b
type parameter is type parameter is
Entrypoint_A of nat Action_A of nat
| Entrypoint_B of string | Action_B of string
type storage is record [ type storage is record [
counter : nat; counter : nat;
@ -117,24 +122,24 @@ type storage is record [
type return is list (operation) * storage type return is list (operation) * storage
function handle_A (const n : nat; const store : storage) : return is function entry_A (const n : nat; const store : storage) : return is
((nil : list (operation)), store with record [counter = n]) ((nil : list (operation)), store with record [counter = n])
function handle_B (const s : string; const store : storage) : return is function entry_B (const s : string; const store : storage) : return is
((nil : list (operation)), store with record [name = s]) ((nil : list (operation)), store with record [name = s])
function main (const param : parameter; const store : storage): return is function access (const action : parameter; const store : storage): return is
case param of case action of
Entrypoint_A (n) -> handle_A (n, store) Action_A (n) -> entry_A (n, store)
| Entrypoint_B (s) -> handle_B (s, store) | Action_B (s) -> entry_B (s, store)
end end
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=b ```cameligo group=b
type parameter = type parameter =
Entrypoint_A of nat Action_A of nat
| Entrypoint_B of string | Action_B of string
type storage = { type storage = {
counter : nat; counter : nat;
@ -143,23 +148,23 @@ type storage = {
type return = operation list * storage type return = operation list * storage
let handle_A (n, store : nat * storage) : return = let entry_A (n, store : nat * storage) : return =
([] : operation list), {store with counter = n} ([] : operation list), {store with counter = n}
let handle_B (s, store : string * storage) : return = let entry_B (s, store : string * storage) : return =
([] : operation list), {store with name = s} ([] : operation list), {store with name = s}
let main (param, store: parameter * storage) : return = let access (action, store: parameter * storage) : return =
match param with match action with
Entrypoint_A n -> handle_A (n, store) Action_A n -> entry_A (n, store)
| Entrypoint_B s -> handle_B (s, store) | Action_B s -> entry_B (s, store)
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=b ```reasonligo group=b
type parameter = type parameter =
| Entrypoint_A (nat) | Action_A (nat)
| Entrypoint_B (string); | Action_B (string);
type storage = { type storage = {
counter : nat, counter : nat,
@ -168,17 +173,16 @@ type storage = {
type return = (list (operation), storage); type return = (list (operation), storage);
let handle_A = ((n, store): (nat, storage)) : return => { let entry_A = ((n, store): (nat, storage)) : return =>
(([] : list (operation)), {...store, counter : n}); }; (([] : list (operation)), {...store, counter : n});
let handle_B = ((s, store): (string, storage)) : return => { let entry_B = ((s, store): (string, storage)) : return =>
(([] : list (operation)), {...store, name : s}); }; (([] : list (operation)), {...store, name : s});
let main = ((param, store): (parameter, storage)) : return => { let access = ((action, store): (parameter, storage)) : return =>
switch (param) { switch (action) {
| Entrypoint_A (n) => handle_A ((n, store)) | Action_A (n) => entry_A ((n, store))
| Entrypoint_B (s) => handle_B ((s, store)) | Action_B (s) => entry_B ((s, store))
}
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
@ -203,7 +207,7 @@ type parameter is unit
type storage is unit type storage is unit
type return is list (operation) * storage type return is list (operation) * storage
function deny (const param : parameter; const store : storage) : return is function deny (const action : parameter; const store : storage) : return is
if amount > 0mutez then if amount > 0mutez then
(failwith ("This contract does not accept tokens.") : return) (failwith ("This contract does not accept tokens.") : return)
else ((nil : list (operation)), store) else ((nil : list (operation)), store)
@ -215,7 +219,7 @@ type parameter = unit
type storage = unit type storage = unit
type return = operation list * storage type return = operation list * storage
let deny (param, store : parameter * storage) : return = let deny (action, store : parameter * storage) : return =
if amount > 0mutez then if amount > 0mutez then
(failwith "This contract does not accept tokens.": return) (failwith "This contract does not accept tokens.": return)
else (([] : operation list), store) else (([] : operation list), store)
@ -227,7 +231,7 @@ type parameter = unit;
type storage = unit; type storage = unit;
type return = (list (operation), storage); type return = (list (operation), storage);
let deny = ((param, store): (parameter, storage)) : return => { let deny = ((action, store): (parameter, storage)) : return => {
if (amount > 0mutez) { if (amount > 0mutez) {
(failwith("This contract does not accept tokens."): return); } (failwith("This contract does not accept tokens."): return); }
else { (([] : list (operation)), store); }; else { (([] : list (operation)), store); };
@ -245,7 +249,7 @@ This example shows how `sender` or `source` can be used to deny access to an ent
```pascaligo group=c ```pascaligo group=c
const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
function filter (const param : parameter; const store : storage) : return is function filter (const action : parameter; const store : storage) : return is
if source =/= owner then (failwith ("Access denied.") : return) if source =/= owner then (failwith ("Access denied.") : return)
else ((nil : list(operation)), store) else ((nil : list(operation)), store)
``` ```
@ -254,7 +258,7 @@ function filter (const param : parameter; const store : storage) : return is
```cameligo group=c ```cameligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)
let filter (param, store: parameter * storage) : return = let filter (action, store: parameter * storage) : return =
if source <> owner then (failwith "Access denied." : return) if source <> owner then (failwith "Access denied." : return)
else (([] : operation list), store) else (([] : operation list), store)
``` ```
@ -263,7 +267,7 @@ let filter (param, store: parameter * storage) : return =
```reasonligo group=c ```reasonligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
let main = ((param, store): (parameter, storage)) : storage => { let access = ((action, store): (parameter, storage)) : storage => {
if (source != owner) { (failwith ("Access denied.") : return); } if (source != owner) { (failwith ("Access denied.") : return); }
else { (([] : list (operation)), store); }; else { (([] : list (operation)), store); };
}; };
@ -289,10 +293,10 @@ emiting a transaction operation at the end of an entrypoint.
> account (tz1, ...): all you have to do is use a unit value as the > account (tz1, ...): all you have to do is use a unit value as the
> parameter of the smart contract. > parameter of the smart contract.
In our case, we have a `counter.ligo` contract that accepts a In our case, we have a `counter.ligo` contract that accepts an action
parameter of type `action`, and we have a `proxy.ligo` contract that of type `parameter`, and we have a `proxy.ligo` contract that accepts
accepts the same parameter type, and forwards the call to the deployed the same parameter type, and forwards the call to the deployed counter
counter contract. contract.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
@ -323,13 +327,13 @@ type return is list (operation) * storage
const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
function proxy (const param : parameter; const store : storage): return is function proxy (const action : parameter; const store : storage): return is
block { block {
const counter : contract (parameter) = get_contract (dest); const counter : contract (parameter) = get_contract (dest);
(* Reuse the parameter in the subsequent (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
const mock_param : parameter = Increment (5n); const mock_param : parameter = Increment (5n);
const op : operation = transaction (param, 0mutez, counter); const op : operation = transaction (action, 0mutez, counter);
const ops : list (operation) = list [op] const ops : list (operation) = list [op]
} with (ops, store) } with (ops, store)
``` ```
@ -338,7 +342,7 @@ function proxy (const param : parameter; const store : storage): return is
```cameligo skip ```cameligo skip
// counter.mligo // counter.mligo
type paramater = type parameter =
Increment of nat Increment of nat
| Decrement of nat | Decrement of nat
| Reset | Reset
@ -360,12 +364,12 @@ type return = operation list * storage
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
let proxy (param, store : parameter * storage) : return = let proxy (action, store : parameter * storage) : return =
let counter : parameter contract = Operation.get_contract dest in let counter : parameter contract = Operation.get_contract dest in
(* Reuse the parameter in the subsequent (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n) in let mock_param : parameter = Increment (5n) in
let op : operation = Operation.transaction param 0mutez counter let op : operation = Operation.transaction action 0mutez counter
in [op], store in [op], store
``` ```
@ -395,12 +399,12 @@ type return = (list (operation), storage);
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address); let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address);
let proxy = ((param, store): (parameter, storage)) : return => { let proxy = ((action, store): (parameter, storage)) : return => {
let counter : contract (parameter) = Operation.get_contract (dest); let counter : contract (parameter) = Operation.get_contract (dest);
(* Reuse the parameter in the subsequent (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n); let mock_param : parameter = Increment (5n);
let op : operation = Operation.transaction (param, 0mutez, counter); let op : operation = Operation.transaction (action, 0mutez, counter);
([op], store) ([op], store)
}; };
``` ```

View File

@ -3,13 +3,12 @@ id: include
title: Including Other Contracts title: Including Other Contracts
--- ---
Lets say we have a contract that's getting a bit too big. If it has a modular Let us say that we have a contract that is getting a too large. If it
structure, you might find it useful to use the `#include` statement to split the has a modular structure, you might find it useful to use the
contract up over multiple files. `#include` statement to split the contract up over multiple files.
You take the code that you want to include and put it in a separate
You take the code that you want to include and put it in a separate file, for file, for example `included.ligo`:
example `included.ligo`:
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
@ -23,7 +22,6 @@ const foo : int = 144
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo
// Demonstrate CameLIGO inclusion statements, see includer.mligo // Demonstrate CameLIGO inclusion statements, see includer.mligo
let foo : int = 144 let foo : int = 144
@ -31,7 +29,6 @@ let foo : int = 144
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
// Demonstrate ReasonLIGO inclusion statements, see includer.religo // Demonstrate ReasonLIGO inclusion statements, see includer.religo
let foo : int = 144; let foo : int = 144;
@ -46,7 +43,6 @@ And then you can include this code using the `#include` statement like so:
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo ```pascaligo
#include "included.ligo" #include "included.ligo"
const bar : int = foo const bar : int = foo
@ -54,7 +50,6 @@ const bar : int = foo
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo
#include "included.mligo" #include "included.mligo"
let bar : int = foo let bar : int = foo
@ -62,7 +57,6 @@ let bar : int = foo
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
#include "included.religo" #include "included.religo"
let bar : int = foo; let bar : int = foo;

View File

@ -33,10 +33,10 @@ let today : timestamp = Current.time;
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
> When running code with ligo CLI, the option > When running code, the LIGO CLI option
> `--predecessor-timestamp` allows you to control what `now` returns. > `--predecessor-timestamp` allows you to control what `now` returns.
### Timestamp Arithmetic ### Timestamp Arithmetics
In LIGO, timestamps can be added to integers, allowing you to set time In LIGO, timestamps can be added to integers, allowing you to set time
constraints on your smart contracts. Consider the following scenarios. constraints on your smart contracts. Consider the following scenarios.
@ -124,9 +124,9 @@ let not_tomorrow : bool = (Current.time == in_24_hrs);
## Addresses ## Addresses
The type `address` in LIGO denotes Tezos addresses (tz1, tz2, tz3, The `address` type in LIGO denotes Tezos addresses (tz1, tz2, tz3,
KT1, ...). Currently, addresses are created by casting a string to the KT1, ...). Currently, addresses are created by casting a string to the
type `address`. Beware of failures if the address is invalid. Consider `address` type. Beware of failures if the address is invalid. Consider
the following examples. the following examples.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->

View File

@ -162,7 +162,7 @@ not worry if it is a little confusing at first; we will explain all
the syntax in the upcoming sections of the documentation. the syntax in the upcoming sections of the documentation.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> <!--PascaLIGO-->
```pascaligo group=a ```pascaligo group=a
type storage is int type storage is int

View File

@ -148,6 +148,29 @@ gitlab-pages/docs/language-basics/boolean-if-else/cond.ligo compare 21n'
# Outputs: Large (Unit) # Outputs: Large (Unit)
``` ```
When the branches of the conditional are not a single expression, as
above, we need a block:
```pascaligo skip
if x < y then
block {
const z : nat = x;
x := y; y := z
}
else skip;
```
As an exception to the rule, the blocks in a conditional branch do not
need to be introduced by the keywor `block`, so, we could have written
instead:
```pascaligo skip
if x < y then {
const z : nat = x;
x := y; y := z
}
else skip;
```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=e ```cameligo group=e
type magnitude = Small | Large // See variant types. type magnitude = Small | Large // See variant types.

View File

@ -3,8 +3,8 @@ id: functions
title: Functions title: Functions
--- ---
LIGO features functions are the basic building block of contracts. For LIGO functions are the basic building block of contracts. For example,
example, entrypoints are functions. entrypoints are functions.
## Declaring Functions ## Declaring Functions
@ -119,8 +119,8 @@ parameter, we should gather the arguments in a
[tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as [tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as
a single parameter. a single parameter.
Here is how you define a basic function that accepts two `ints` and Here is how you define a basic function that accepts two integers and
returns an `int` as well: returns an integer as well:
```cameligo group=b ```cameligo group=b
let add (a, b : int * int) : int = a + b // Uncurried let add (a, b : int * int) : int = a + b // Uncurried
@ -137,10 +137,11 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/curry.mligo in
The function body is a single expression, whose value is returned. The function body is a single expression, whose value is returned.
<!--ReasonLIGO--> Functions in ReasonLIGO are defined using the `let` <!--ReasonLIGO-->
keyword, like other values. The difference is that a tuple of
parameters is provided after the value name, with its type, then Functions in ReasonLIGO are defined using the `let` keyword, like
followed by the return type. other values. The difference is that a tuple of parameters is provided
after the value name, with its type, then followed by the return type.
Here is how you define a basic function that sums two integers: Here is how you define a basic function that sums two integers:
```reasonligo group=b ```reasonligo group=b
@ -154,7 +155,19 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.reli
# Outputs: 3 # Outputs: 3
``` ```
The function body is a single expression, whose value is returned. As in CameLIGO and with blockless functions in PascaLIGO, the function
body is a single expression, whose value is returned.
If the body contains more than a single expression, you use block
between braces:
```reasonligo group=b
let myFun = ((x, y) : (int, int)) : int => {
let doubleX = x + x;
let doubleY = y + y;
doubleX + doubleY
};
```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
## Anonymous functions (a.k.a. lambdas) ## Anonymous functions (a.k.a. lambdas)
@ -170,7 +183,6 @@ Here is how to define an anonymous function:
```pascaligo group=c ```pascaligo group=c
function increment (const b : int) : int is function increment (const b : int) : int is
(function (const a : int) : int is a + 1) (b) (function (const a : int) : int is a + 1) (b)
const a : int = increment (1); // a = 2 const a : int = increment (1); // a = 2
``` ```
@ -257,5 +269,4 @@ gitlab-pages/docs/language-basics/src/functions/incr_map.religo incr_map
# Outputs: [ 2 ; 3 ; 4 ] # Outputs: [ 2 ; 3 ; 4 ]
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -20,13 +20,12 @@ loops fails to become true, the execution will run out of gas and stop
with a failure anyway. with a failure anyway.
Here is how to compute the greatest common divisors of two natural Here is how to compute the greatest common divisors of two natural
number by means of Euclid's algorithm: numbers by means of Euclid's algorithm:
```pascaligo group=a ```pascaligo group=a
function gcd (var x : nat; var y : nat) : nat is function gcd (var x : nat; var y : nat) : nat is
block { block {
if x < y then if x < y then {
block {
const z : nat = x; const z : nat = x;
x := y; y := z x := y; y := z
} }
@ -55,18 +54,19 @@ constant, therefore it makes no sense in CameLIGO to feature loops,
which we understand as syntactic constructs where the state of a which we understand as syntactic constructs where the state of a
stopping condition is mutated, as with "while" loops in PascaLIGO. stopping condition is mutated, as with "while" loops in PascaLIGO.
Instead, CameLIGO features a *fold operation* as a predefined function Instead, CameLIGO implements a *folded operation* by means of a
named `Loop.fold_while`. It takes an initial value of a certain type, predefined function named `Loop.fold_while`. It takes an initial value
called an *accumulator*, and repeatedly calls a given function, called of a certain type, called an *accumulator*, and repeatedly calls a
*iterated function*, that takes that accumulator and returns the next given function, called *folded function*, that takes that
value of the accumulator, until a condition is met and the fold stops accumulator and returns the next value of the accumulator, until a
with the final value of the accumulator. The iterated function needs condition is met and the fold stops with the final value of the
to have a special type: if the type of the accumulator is `t`, then it accumulator. The iterated function needs to have a special type: if
must have the type `bool * t` (not simply `t`). It is the boolean the type of the accumulator is `t`, then it must have the type `bool *
value that denotes whether the stopping condition has been reached. t` (not simply `t`). It is the boolean value that denotes whether the
stopping condition has been reached.
Here is how to compute the greatest common divisors of two natural Here is how to compute the greatest common divisors of two natural
number by means of Euclid's algorithm: numbers by means of Euclid's algorithm:
```cameligo group=a ```cameligo group=a
let iter (x,y : nat * nat) : bool * (nat * nat) = let iter (x,y : nat * nat) : bool * (nat * nat) =
@ -117,7 +117,7 @@ accumulator is `t`, then it must have the type `bool * t` (not simply
condition has been reached. condition has been reached.
Here is how to compute the greatest common divisors of two natural Here is how to compute the greatest common divisors of two natural
number by means of Euclid's algorithm: numbers by means of Euclid's algorithm:
```reasonligo group=a ```reasonligo group=a
let iter = ((x,y) : (nat, nat)) : (bool, (nat, nat)) => let iter = ((x,y) : (nat, nat)) : (bool, (nat, nat)) =>
@ -149,11 +149,10 @@ let gcd = ((x,y) : (nat, nat)) : nat => {
In addition to general loops, PascaLIGO features a specialised kind of In addition to general loops, PascaLIGO features a specialised kind of
*loop to iterate over bounded intervals*. These loops are familiarly *loop to iterate over bounded intervals*. These loops are familiarly
known as "for loops" and they have the form `for <variable assignment> to known as "for loops" and they have the form `for <variable assignment>
<upper bound> <block>`, which is familiar for programmers of to <upper bound> <block>`, as found in imperative languages.
imperative languages.
Consider how to sum integers from `0` to `n`: Consider how to sum the natural numbers up to `n`:
```pascaligo group=c ```pascaligo group=c
function sum (var n : nat) : int is block { function sum (var n : nat) : int is block {
@ -177,7 +176,7 @@ gitlab-pages/docs/language-basics/src/loops/sum.ligo sum 7n
PascaLIGO "for" loops can also iterate through the contents of a PascaLIGO "for" loops can also iterate through the contents of a
collection, that is, a list, a set or a map. This is done with a loop collection, that is, a list, a set or a map. This is done with a loop
of the form `for <element var> in <collection type> <collection var> of the form `for <element var> in <collection type> <collection var>
<block>`, where `<collection type` is any of the following keywords: <block>`, where `<collection type>` is any of the following keywords:
`list`, `set` or `map`. `list`, `set` or `map`.
Here is an example where the integers in a list are summed up. Here is an example where the integers in a list are summed up.
@ -202,7 +201,7 @@ gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_list
Here is an example where the integers in a set are summed up. Here is an example where the integers in a set are summed up.
```pascaligo=e ```pascaligo group=d
function sum_set (var s : set (int)) : int is block { function sum_set (var s : set (int)) : int is block {
var total : int := 0; var total : int := 0;
for i in set s block { for i in set s block {
@ -222,9 +221,23 @@ gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_set
Loops over maps are actually loops over the bindings of the map, that Loops over maps are actually loops over the bindings of the map, that
is, a pair key-value noted `key -> value` (or any other is, a pair key-value noted `key -> value` (or any other
variables). Give a map from strings to integers, here is how to sum variables). Given a map from strings to integers, here is how to sum
all the integers and concatenate all the strings. all the integers and concatenate all the strings.
Here is an example where the keys are concatenated and the values are
summed up.
```pascaligo group=d
function sum_map (var m : map (string, int)) : string * int is block {
var string_total : string := "";
var int_total : int := 0;
for key -> value in map m block {
string_total := string_total ^ key;
int_total := int_total + value
}
} with (string_total, int_total)
```
You can call the function `sum_map` defined above using the LIGO compiler You can call the function `sum_map` defined above using the LIGO compiler
like so: like so:
```shell ```shell

View File

@ -110,9 +110,7 @@ modified.
One way to understand the update of record values is the *functional One way to understand the update of record values is the *functional
update*. The idea is to have an *expression* whose value is the update*. The idea is to have an *expression* whose value is the
updated record. The shape of that expression is `<record variable> updated record.
with <record value>`. The record variable is the record to update and
the record value is the update itself.
Let us consider defining a function that translates three-dimensional Let us consider defining a function that translates three-dimensional
points on a plane. points on a plane.
@ -120,6 +118,11 @@ points on a plane.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the shape of that expression is `<record variable> with
<record value>`. The record variable is the record to update and the
record value is the update itself.
```pascaligo group=b ```pascaligo group=b
type point is record [x : int; y : int; z : int] type point is record [x : int; y : int; z : int]
type vector is record [dx : int; dy : int] type vector is record [dx : int; dy : int]
@ -174,7 +177,7 @@ xy_translate "({x=2;y=3;z=1}, {dx=3;dy=4})"
<!--ReasonLIGO--> <!--ReasonLIGO-->
The syntax for the functional updates of record in ReasonLIGO follows The syntax for the functional updates of record in ReasonLIGO follows
that of OCaml: that of ReasonML:
```reasonligo group=b ```reasonligo group=b
type point = {x : int, y : int, z : int}; type point = {x : int, y : int, z : int};
@ -199,7 +202,7 @@ xy_translate "({x:2,y:3,z:1}, {dx:3,dy:4})"
You have to understand that `p` has not been changed by the functional You have to understand that `p` has not been changed by the functional
update: a nameless new version of it has been created and returned. update: a nameless new version of it has been created and returned.
### Imperative Updates ### Record Patches
Another way to understand what it means to update a record value is to Another way to understand what it means to update a record value is to
make sure that any further reference to the value afterwards will make sure that any further reference to the value afterwards will
@ -365,12 +368,13 @@ let moves : register =
### Accessing Map Bindings ### Accessing Map Bindings
We can use the postfix `[]` operator to read the `move` value
associated to a given key (`address` here) in the register. Here is an
example:
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, we can use the postfix `[]` operator to read the `move`
value associated to a given key (`address` here) in the register. Here
is an example:
```pascaligo group=f ```pascaligo group=f
const my_balance : option (move) = const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)] moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
@ -480,10 +484,9 @@ We can update a binding in a map in ReasonLIGO by means of the
`Map.update` built-in function: `Map.update` built-in function:
```reasonligo group=f ```reasonligo group=f
let assign = (m : register) : register => { let assign = (m : register) : register =>
Map.update Map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m) (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m);
};
``` ```
> Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had > Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
@ -521,9 +524,8 @@ let delete (key, moves : address * register) : register =
In ReasonLIGO, we use the predefined function `Map.remove` as follows: In ReasonLIGO, we use the predefined function `Map.remove` as follows:
```reasonligo group=f ```reasonligo group=f
let delete = ((key, moves) : (address, register)) : register => { let delete = ((key, moves) : (address, register)) : register =>
Map.remove (key, moves); Map.remove (key, moves);
};
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
@ -540,7 +542,7 @@ There are three kinds of functional iterations over LIGO maps: the
*iterated operation*, the *map operation* (not to be confused with the *iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*. *map data structure*) and the *fold operation*.
#### Iterated Operation #### Iterated Operation over Maps
The first, the *iterated operation*, is an iteration over the map with 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 no return value: its only use is to produce side-effects. This can be
@ -595,7 +597,7 @@ let iter_op = (m : register) : unit => {
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Map Operation #### Map Operations over Maps
We may want to change all the bindings of a map by applying to them a 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 function. This is called a *map operation*, not to be confused with
@ -643,9 +645,9 @@ let map_op = (m : register) : register => {
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Fold Operation #### Folded Operations over Maps
A *fold operation* is the most general of iterations. The folded A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This *element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the enables having a partial result that becomes complete when the
@ -655,14 +657,15 @@ traversal of the data structure is over.
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the fold In PascaLIGO, the predefined functional iterator implementing the
operation over maps is called `map_fold` and is used as follows: folded operation over maps is called `map_fold` and is used as
follows:
```pascaligo group=f ```pascaligo group=f
function fold_op (const m : register) : int is block { function fold_op (const m : register) : int is block {
function iterated (const j : int; const cur : address * move) : int is function folded (const j : int; const cur : address * move) : int is
j + cur.1.1 j + cur.1.1
} with map_fold (iterated, m, 5) } with map_fold (folded, m, 5)
``` ```
> The folded function must be pure, that is, it cannot mutate > The folded function must be pure, that is, it cannot mutate
@ -670,24 +673,26 @@ function fold_op (const m : register) : int is block {
<!--CameLIGO--> <!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the fold In CameLIGO, the predefined functional iterator implementing the
operation over maps is called `Map.fold` and is used as follows: folded operation over maps is called `Map.fold` and is used as
follows:
```cameligo group=f ```cameligo group=f
let fold_op (m : register) : register = let fold_op (m : register) : register =
let iterated = fun (i,j : int * (address * move)) -> i + j.1.1 let folded = fun (i,j : int * (address * move)) -> i + j.1.1
in Map.fold iterated m 5 in Map.fold folded m 5
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the In ReasonLIGO, the predefined functional iterator implementing the
fold operation over maps is called `Map.fold` and is used as follows: folded operation over maps is called `Map.fold` and is used as
follows:
```reasonligo group=f ```reasonligo group=f
let fold_op = (m : register) : register => { let fold_op = (m : register) : register => {
let iterated = ((i,j): (int, (address, move))) => i + j[1][1]; let folded = ((i,j): (int, (address, move))) => i + j[1][1];
Map.fold (iterated, m, 5); Map.fold (folded, m, 5);
}; };
``` ```

View File

@ -60,13 +60,13 @@ let b : int = 5n + 10
let c : tez = 5mutez + 10mutez let c : tez = 5mutez + 10mutez
// tez + int or tez + nat is invalid // tez + int or tez + nat is invalid
// const d : tez = 5mutez + 10n // let d : tez = 5mutez + 10n
// two nats yield a nat // two nats yield a nat
let e : nat = 5n + 10n let e : nat = 5n + 10n
// nat + int yields an int: invalid // nat + int yields an int: invalid
// const f : nat = 5n + 10 // let f : nat = 5n + 10
let g : int = 1_000_000 let g : int = 1_000_000
``` ```
@ -136,7 +136,7 @@ let a : int = 5 - 10
let b : int = 5n - 2n let b : int = 5n - 2n
// Therefore the following is invalid // Therefore the following is invalid
// const c : nat = 5n - 2n // let c : nat = 5n - 2n
let d : tez = 5mutez - 1mutez let d : tez = 5mutez - 1mutez
``` ```
@ -167,15 +167,17 @@ You can multiply values of the same type, such as:
```pascaligo group=c ```pascaligo group=c
const a : int = 5 * 5 const a : int = 5 * 5
const b : nat = 5n * 5n const b : nat = 5n * 5n
// You can also multiply `nat` and `tez` in any order
const c : tez = 5n * 5mutez; // You can also multiply `nat` and `tez`
const c : tez = 5n * 5mutez
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=c ```cameligo group=c
let a : int = 5 * 5 let a : int = 5 * 5
let b : nat = 5n * 5n let b : nat = 5n * 5n
// You can also multiply `nat` and `tez` in any order
// You can also multiply `nat` and `tez`
let c : tez = 5n * 5mutez let c : tez = 5n * 5mutez
``` ```
@ -183,7 +185,8 @@ let c : tez = 5n * 5mutez
```reasonligo group=c ```reasonligo group=c
let a : int = 5 * 5; let a : int = 5 * 5;
let b : nat = 5n * 5n; let b : nat = 5n * 5n;
// You can also multiply `nat` and `tez` in any order
// You can also multiply `nat` and `tez`
let c : tez = 5n * 5mutez; let c : tez = 5n * 5mutez;
``` ```

View File

@ -13,10 +13,10 @@ values, called *components*, can be retrieved by their index
(position). Probably the most common tuple is the *pair*. For (position). Probably the most common tuple is the *pair*. For
example, if we were storing coordinates on a two dimensional grid we example, if we were storing coordinates on a two dimensional grid we
might use a pair `(x,y)` to store the coordinates `x` and `y`. There might use a pair `(x,y)` to store the coordinates `x` and `y`. There
is a *specific order*, so `(y,x)` is not equal to `(x,y)`. The number is a *specific order*, so `(y,x)` is not equal to `(x,y)` in
of components is part of the type of a tuple, so, for example, we general. The number of components is part of the type of a tuple, so,
cannot add an extra component to a pair and obtain a triple of the for example, we cannot add an extra component to a pair and obtain a
same type, so, for instance, `(x,y)` has always a different type from triple of the same type: `(x,y)` has always a different type from
`(x,y,z)`, whereas `(y,x)` might have the same type as `(x,y)`. `(x,y,z)`, whereas `(y,x)` might have the same type as `(x,y)`.
Like records, tuple components can be of arbitrary types. Like records, tuple components can be of arbitrary types.
@ -68,10 +68,10 @@ position in their tuple, which cannot be done in OCaml.
<!--PascaLIGO--> <!--PascaLIGO-->
Tuple components are one-indexed like so: Tuple components are one-indexed and accessed like so:
```pascaligo group=tuple ```pascaligo group=tuple
const first_name : string = full_name.1; const first_name : string = full_name.1
``` ```
<!--CameLIGO--> <!--CameLIGO-->
@ -84,7 +84,7 @@ let first_name : string = full_name.0
<!--ReasonLIGO--> <!--ReasonLIGO-->
Tuple components are one-indexed like so: Tuple components are one-indexed and accessed like so:
```reasonligo group=tuple ```reasonligo group=tuple
let first_name : string = full_name[1]; let first_name : string = full_name[1];
@ -102,24 +102,27 @@ called the *head*, and the sub-list after the head is called the
*tail*. For those familiar with algorithmic data structure, you can *tail*. For those familiar with algorithmic data structure, you can
think of a list a *stack*, where the top is written on the left. think of a list a *stack*, where the top is written on the left.
> 💡 Lists are useful when returning operations from a smart > 💡 Lists are needed when returning operations from a smart
> contract's entrypoint. > contract's access function.
### Defining Lists ### Defining Lists
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo group=lists ```pascaligo group=lists
const empty_list : list (int) = nil // Or list []
const my_list : list (int) = list [1; 2; 2] // The head is 1 const my_list : list (int) = list [1; 2; 2] // The head is 1
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=lists ```cameligo group=lists
let empty_list : int list = []
let my_list : int list = [1; 2; 2] // The head is 1 let my_list : int list = [1; 2; 2] // The head is 1
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=lists ```reasonligo group=lists
let empty_list : list (int) = [];
let my_list : list (int) = [1, 2, 2]; // The head is 1 let my_list : list (int) = [1, 2, 2]; // The head is 1
``` ```
@ -128,7 +131,6 @@ 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 Lists can be augmented by adding an element before the head (or, in
terms of stack, by *pushing an element on top*). This operation is terms of stack, by *pushing an element on top*). This operation is
usually called *consing* in functional languages. usually called *consing* in functional languages.
@ -167,12 +169,6 @@ let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2]
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
> 💡 Lists can be iterated, folded or mapped to different values. You
> can find additional examples
> [here](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts)
> and other built-in operators
> [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L59)
### Functional Iteration over Lists ### Functional Iteration over Lists
A *functional iterator* is a function that traverses a data structure A *functional iterator* is a function that traverses a data structure
@ -180,16 +176,23 @@ and calls in turn a given function over the elements of that structure
to compute some value. Another approach is possible in PascaLIGO: to compute some value. Another approach is possible in PascaLIGO:
*loops* (see the relevant section). *loops* (see the relevant section).
There are three kinds of functional iterations over LIGO maps: the There are three kinds of functional iterations over LIGO lists: the
*iterated operation*, the *map operation* (not to be confused with the *iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*. *map data structure*) and the *fold operation*.
#### Iterated Operation > 💡 Lists can be iterated, folded or mapped to different values. You
> can find additional examples
> [here](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts)
> and other built-in operators
> [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L59)
The first, the *iterated operation*, is an iteration over the map with #### Iterated Operation over Lists
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 The first, the *iterated operation*, is an iteration over the list
of a map is within a certain range, and fail with an error otherwise. 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.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
@ -244,7 +247,7 @@ let iter_op = (l : list (int)) : unit => {
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Map Operation #### Mapped Operation over Lists
We may want to change all the elements of a given list by applying to 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 them a function. This is called a *map operation*, not to be confused
@ -254,8 +257,9 @@ with the map data structure.
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the map In PascaLIGO, the predefined functional iterator implementing the
operation over lists is called `list_map` and is used as follows: mapped operation over lists is called `list_map` and is used as
follows:
```pascaligo group=lists ```pascaligo group=lists
function increment (const i : int): int is i + 1 function increment (const i : int): int is i + 1
@ -264,10 +268,14 @@ function increment (const i : int): int is i + 1
const plus_one : list (int) = list_map (increment, larger_list) const plus_one : list (int) = list_map (increment, larger_list)
``` ```
> The mapped function must be pure, that is, it cannot mutate
> variables.
<!--CameLIGO--> <!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the map In CameLIGO, the predefined functional iterator implementing the
operation over lists is called `List.map` and is used as follows: mapped operation over lists is called `List.map` and is used as
follows:
```cameligo group=lists ```cameligo group=lists
let increment (i : int) : int = i + 1 let increment (i : int) : int = i + 1
@ -278,8 +286,9 @@ let plus_one : int list = List.map increment larger_list
<!--ReasonLIGO--> <!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the map In ReasonLIGO, the predefined functional iterator implementing the
operation over lists is called `List.map` and is used as follows: mapped operation over lists is called `List.map` and is used as
follows:
```reasonligo group=lists ```reasonligo group=lists
let increment = (i : int) : int => i + 1; let increment = (i : int) : int => i + 1;
@ -290,9 +299,9 @@ let plus_one : list (int) = List.map (increment, larger_list);
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Fold Operation #### Folded Operation over Lists
A *fold operation* is the most general of iterations. The folded A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This *element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the enables having a partial result that becomes complete when the
@ -302,12 +311,12 @@ traversal of the data structure is over.
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the fold In PascaLIGO, the predefined functional iterator implementing the
operation over lists is called `list_fold` and is used as follows: folded operation over lists is called `list_fold` and is used as
follows:
```pascaligo group=lists ```pascaligo group=lists
function sum (const acc : int; const i : int): int is acc + i 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)
``` ```
@ -316,7 +325,7 @@ const sum_of_elements : int = list_fold (sum, my_list, 0)
<!--CameLIGO--> <!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the fold In CameLIGO, the predefined functional iterator implementing the folded
operation over lists is called `List.fold` and is used as follows: operation over lists is called `List.fold` and is used as follows:
```cameligo group=lists ```cameligo group=lists
@ -327,7 +336,8 @@ let sum_of_elements : int = List.fold sum my_list 0
<!--ReasonLIGO--> <!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the In ReasonLIGO, the predefined functional iterator implementing the
fold operation over lists is called `List.fold` and is used as follows: folded operation over lists is called `List.fold` and is used as
follows:
```reasonligo group=lists ```reasonligo group=lists
let sum = ((result, i): (int, int)): int => result + i; let sum = ((result, i): (int, int)): int => result + i;
@ -365,7 +375,7 @@ let my_set : int set = Set.empty
<!--ReasonLIGO--> <!--ReasonLIGO-->
In CameLIGO, the empty set is denoted by the predefined value In ReasonLIGO, the empty set is denoted by the predefined value
`Set.empty`. `Set.empty`.
```reasonligo group=sets ```reasonligo group=sets
@ -469,7 +479,7 @@ let contains_3 : bool = Set.mem (3, my_set);
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
### Cardinal ### Cardinal of Sets
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
@ -509,7 +519,7 @@ let set_size : nat = Set.size (my_set);
In PascaLIGO, there are two ways to update a set, that is to add or In PascaLIGO, there are two ways to update a set, that is to add or
remove from it. Either we create a new set from the given one, or we remove from it. Either we create a new set from the given one, or we
modify it in-place. First, let us consider the former way modify it in-place. First, let us consider the former way:
```pascaligo group=sets ```pascaligo group=sets
const larger_set : set (int) = set_add (4, my_set) const larger_set : set (int) = set_add (4, my_set)
@ -568,8 +578,8 @@ to compute some value. Another approach is possible in PascaLIGO:
*loops* (see the relevant section). *loops* (see the relevant section).
There are three kinds of functional iterations over LIGO maps: the There are three kinds of functional iterations over LIGO maps: the
*iterated operation*, the *map operation* (not to be confused with the *iterated operation*, the *mapped operation* (not to be confused with
*map data structure*) and the *fold operation*. the *map data structure*) and the *folded operation*.
#### Iterated Operation #### Iterated Operation
@ -631,18 +641,18 @@ let iter_op = (s : set (int)) : unit => {
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Map Operation #### Mapped Operation (NOT IMPLEMENTED YET)
We may want to change all the elements of a given set by applying to We may want to change all the elements of a given set by applying to
them a function. This is called a *map operation*, not to be confused them a function. This is called a *mapped operation*, not to be
with the map data structure. confused with the map data structure.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the map In PascaLIGO, the predefined functional iterator implementing the
operation over sets is called `set_map` and is used as follows: mapped operation over sets is called `set_map` and is used as follows:
```pascaligo skip ```pascaligo skip
function increment (const i : int): int is i + 1 function increment (const i : int): int is i + 1
@ -653,8 +663,8 @@ const plus_one : set (int) = set_map (increment, larger_set)
<!--CameLIGO--> <!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the map In CameLIGO, the predefined functional iterator implementing the
operation over sets is called `Set.map` and is used as follows: mapped operation over sets is called `Set.map` and is used as follows:
```cameligo skip ```cameligo skip
let increment (i : int) : int = i + 1 let increment (i : int) : int = i + 1
@ -663,11 +673,10 @@ let increment (i : int) : int = i + 1
let plus_one : int set = Set.map increment larger_set let plus_one : int set = Set.map increment larger_set
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the map In ReasonLIGO, the predefined functional iterator implementing the
operation over sets is called `Set.map` and is used as follows: mapped operation over sets is called `Set.map` and is used as follows:
```reasonligo skip ```reasonligo skip
let increment = (i : int) : int => i + 1; let increment = (i : int) : int => i + 1;
@ -678,9 +687,9 @@ let plus_one : set (int) = Set.map (increment, larger_set);
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
#### Fold Operation #### Folded Operation
A *fold operation* is the most general of iterations. The folded A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This *element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the enables having a partial result that becomes complete when the
@ -690,8 +699,9 @@ traversal of the data structure is over.
<!--PascaLIGO--> <!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the fold In PascaLIGO, the predefined functional iterator implementing the
operation over sets is called `set_fold` and is used as follows: folded operation over sets is called `set_fold` and is used as
follows:
```pascaligo group=sets ```pascaligo group=sets
function sum (const acc : int; const i : int): int is acc + i function sum (const acc : int; const i : int): int is acc + i

View File

@ -27,7 +27,7 @@ let a : string = "Hello Alice";
<!--PascaLIGO--> <!--PascaLIGO-->
Strings can be concatenated using the `^` operator. Strings can be concatenated using the `^` operator.
```pascaligo ```pascaligo group=a
const name : string = "Alice" const name : string = "Alice"
const greeting : string = "Hello" const greeting : string = "Hello"
const full_greeting : string = greeting ^ " " ^ name const full_greeting : string = greeting ^ " " ^ name
@ -35,7 +35,7 @@ const full_greeting : string = greeting ^ " " ^ name
<!--CameLIGO--> <!--CameLIGO-->
Strings can be concatenated using the `^` operator. Strings can be concatenated using the `^` operator.
```cameligo ```cameligo group=a
let name : string = "Alice" let name : string = "Alice"
let greeting : string = "Hello" let greeting : string = "Hello"
let full_greeting : string = greeting ^ " " ^ name let full_greeting : string = greeting ^ " " ^ name
@ -43,7 +43,7 @@ let full_greeting : string = greeting ^ " " ^ name
<!--ReasonLIGO--> <!--ReasonLIGO-->
Strings can be concatenated using the `++` operator. Strings can be concatenated using the `++` operator.
```reasonligo ```reasonligo group=a
let name : string = "Alice"; let name : string = "Alice";
let greeting : string = "Hello"; let greeting : string = "Hello";
let full_greeting : string = greeting ++ " " ++ name; let full_greeting : string = greeting ++ " " ++ name;
@ -57,17 +57,17 @@ Strings can be sliced using a built-in function:
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo ```pascaligo group=b
const name : string = "Alice" const name : string = "Alice"
const slice : string = string_slice (0n, 1n, name) const slice : string = string_slice (0n, 1n, name)
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo group=b
let name : string = "Alice" let name : string = "Alice"
let slice : string = String.slice 0n 1n name let slice : string = String.slice 0n 1n name
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo group=b
let name : string = "Alice"; let name : string = "Alice";
let slice : string = String.slice (0n, 1n, name); let slice : string = String.slice (0n, 1n, name);
``` ```
@ -81,18 +81,18 @@ The length of a string can be found using a built-in function:
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo ```pascaligo group=c
const name : string = "Alice" const name : string = "Alice"
const length : nat = size (name) // length = 5 const length : nat = size (name) // length = 5
``` ```
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo group=c
let name : string = "Alice" let name : string = "Alice"
let length : nat = String.size name // length = 5 let length : nat = String.size name // length = 5
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo group=c
let name : string = "Alice"; let name : string = "Alice";
let length : nat = String.size (name); // length == 5 let length : nat = String.size (name); // length == 5
``` ```

View File

@ -10,16 +10,15 @@ functions. This page will tell you about them.
## Pack and Unpack ## Pack and Unpack
Michelson provides the `PACK` and `UNPACK` instructions for data Michelson provides the `PACK` and `UNPACK` instructions for data
serialization. The instruction `PACK` converts Michelson data serialization. The former converts Michelson data structures into a
structures into a binary format, and `UNPACK` reverses that binary format, and the latter reverses that transformation. This
transformation. This functionality can be accessed from within LIGO. functionality can be accessed from within LIGO.
> ⚠️ `PACK` and `UNPACK` are Michelson instructions that are intended > ⚠️ `PACK` and `UNPACK` are Michelson instructions that are intended
> to be used by people that really know what they are doing. There are > to be used by people that really know what they are doing. There are
> several risks and failure cases, such as unpacking a lambda from an > several risks and failure cases, such as unpacking a lambda from an
> untrusted source, and most of which are beyond the scope of this > untrusted source or casting the result to the wrong type. Do not use
> document. Do not use these functions without doing your homework > the corresponding LIGO functions without doing your homework first.
> first.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
@ -116,9 +115,8 @@ let check_signature (pk, signed, msg : key * signature * bytes) : bool =
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=c ```reasonligo group=c
let check_signature = let check_signature =
((pk, signed, msg) : (key, signature, bytes)) : bool => { ((pk, signed, msg) : (key, signature, bytes)) : bool =>
Crypto.check (pk, signed, msg); Crypto.check (pk, signed, msg);
};
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
@ -129,8 +127,8 @@ Often you want to get the address of the contract being executed. You
can do it with `self_address`. can do it with `self_address`.
> ⚠️ Due to limitations in Michelson, `self_address` in a contract is > ⚠️ Due to limitations in Michelson, `self_address` in a contract is
> only allowed at the entrypoint level, that is, at the > only allowed at the top-level. Using it in an embedded function will
> top-level. Using it in an embedded function will cause an error. > cause an error.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->

View File

@ -53,13 +53,12 @@ let dog_breed : breed = "Saluki";
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <!--PascaLIGO-->
```pascaligo group=b ```pascaligo group=b
// The type accountBalances denotes maps from addresses to tez // The type account_balances denotes maps from addresses to tez
type account_balances is map (address, tez) type account_balances is map (address, tez)
const ledger : account_balances = const ledger : account_balances =
map [("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> 10mutez] map [("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> 10mutez]
``` ```
<!--CameLIGO--> <!--CameLIGO-->

View File

@ -69,7 +69,8 @@ or as function parameters.
function add (const a : int; const b : int) : int is function add (const a : int; const b : int) : int is
block { block {
var c : int := a + b var c : int := a + 2*b;
c := c - b
} with c } with c
``` ```

View File

@ -0,0 +1,268 @@
---
id: big-map-reference
title: Big Map
---
## Defining A Big Map Type
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type move is (int * int)
type moveset is big_map (address, move)
type foo is big_map (int, int)
```
<!--CameLIGO-->
```cameligo
type move = int * int
type moveset = (address, move) big_map
type foo = (int, int) big_map
```
<!--ReasonLIGO-->
```reasonligo
type move = (int, int);
type moveset = big_map(address, move);
type foo = big_map(int, int);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Creating A Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset =
big_map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
end
```
<!--CameLIGO-->
```cameligo
let moves: moveset =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
]
```
<!--ReasonLIGO-->
```reasonligo
let moves: moveset =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)),
]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.find_opt(k: a', m: (a',b') big_map) : b' option
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.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : option(move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)]
```
<!--CameLIGO-->
```cameligo
let my_balance : move option =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : option(move) =
Big_map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.find(k: a', m: (a', b') big_map) : b'
Forcefully retrieve the value associated with a particular key. If that value
doesn't exist, this function throws an error.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : move =
get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
```
<!--CameLIGO-->
```cameligo
let my_balance : move =
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : move =
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.update(k: a', v: b', m: (a', b') big_map) : (a', b') big_map
Change the value associated with a particular key, if that value doesn't already
exist add it.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
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);
} with m
```
<!--Cameligo-->
```cameligo
let updated_map : moveset =
Big_map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) (Some (4,9)) moves
```
<!--Reasonligo-->
```reasonligo
let updated_map : moveset =
Big_map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.add(k: a', v: b', m: (a', b') big_map) : (a', b') big_map
Add a key and its associated value to the big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function set_ (var n : int ; var m : foo) : foo is block {
m[23] := n ;
} with m
```
<!--CameLIGO-->
```cameligo
let add (n,m : int * foo) : foo = Big_map.add 23 n m
```
<!--ReasonLIGO-->
```reasonligo
let add = ((n,m): (int, foo)): foo => Big_map.add(23, n, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.remove(k: a', m: (a', b') big_map) : (a', b') big_map
Remove a key and its associated value from the big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function rm (var m : foo) : foo is block {
remove 42 from map m;
} with m
```
<!--CameLIGO-->
```cameligo
let rm (m : foo) : foo = Big_map.remove 42 m
```
<!--ReasonLIGO-->
```reasonligo
let rm = (m: foo): foo => Big_map.remove(42, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.literal(key_value_pair_list: (a', b') list) : (a', b') big_map
Constructs a big map from a list of key-value pair tuples.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset =
big_map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
end
```
<!--CameLIGO-->
```cameligo
let moves: moveset =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
]
```
<!--ReasonLIGO-->
```reasonligo
let moves: moveset =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)),
]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.empty() : (a', b') big_map
Create an empty big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const empty_big_map : big_map(int,int) = big_map end
```
<!--CameLIGO-->
```cameligo
let empty_map : foo = Big_map.empty
```
<!--ReasonLIGO-->
```reasonligo
let empty_map: foo = Big_map.empty;
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,201 @@
---
id: set-reference
title: Set
---
## Defining a set
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
type int_set is set (int);
const my_set : int_set = set 1; 2; 3 end
```
<!--CameLIGO-->
```cameligo group=a
type int_set = int set
let my_set : int_set =
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
```
<!--ReasonLIGO-->
```reasonligo group=a
type int_set = set (int);
let my_set : int_set =
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.mem(is_member: a', s: a' set) : bool
Check if a set `s` contains the element `is_member`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const contains_three : bool = my_set contains 3
// or alternatively
const contains_three_fn: bool = set_mem (3, my_set);
```
<!--CameLIGO-->
```cameligo group=a
let contains_three: bool = Set.mem 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let contains_three: bool = Set.mem(3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.empty() : a' set
Create a new empty set. Needs to be annotated with the set type.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const my_set: int_set = set end
const my_set_2: int_set = set_empty
```
<!--CameLIGO-->
```cameligo group=a
let my_set: int_set = (Set.empty: int set)
```
<!--ReasonLIGO-->
```reasonligo group=a
let my_set: int_set = (Set.empty: set (int));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.literal(element_list_literal: 'a list) : 'a set
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.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const s_fb : set(string) = set [
"foo" ;
"bar" ;
]
```
<!--CameLIGO-->
```cameligo
let literal_op (p: unit) : string set =
Set.literal ["foo"; "bar"; "foobar"]
```
<!--ReasonLIGO-->
```reasonligo
let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.add(addition: a', s: a' set) : a' set
Add the element `addition` to a set `s`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
function add_op (const s : set(string)) : set(string) is
begin skip end with set_add("foobar" , s)
```
<!--CameLIGO-->
```cameligo group=a
type int_set = int set
let my_set : int_set =
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
```
<!--ReasonLIGO-->
```reasonligo group=a
type int_set = set (int);
let my_set : int_set =
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.remove(removal: a', s: a' set) : a' set
Remove the element `removal` from a set `s`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const smaller_set: int_set = set_remove(3, my_set);
```
<!--CameLIGO-->
```cameligo group=a
let smaller_set: int_set = Set.remove 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let smaller_set: int_set = Set.remove(3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.fold(folding_function: a' -> a' -> a', s: a' set, initial: a') : a'
Combine the elements of a set into a single value using a folding function.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
function sum(const result: int; const i: int): int is result + i;
// Outputs 6
const sum_of_a_set: int = set_fold(sum, my_set, 0);
```
<!--CameLIGO-->
```cameligo group=a
let sum (result, i: int * int) : int = result + i
let sum_of_a_set: int = Set.fold sum my_set 0
```
<!--ReasonLIGO-->
```reasonligo group=a
let sum = (result_i: (int, int)): int => result_i[0] + result_i[1];
let sum_of_a_set: int = Set.fold(sum, my_set, 0);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.size(s: a' set) : nat
Get the number of elements in a set.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const set_size: nat = size (my_set)
```
<!--CameLIGO-->
```cameligo group=a
let set_size: nat = Set.size my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let set_size: nat = Set.size (my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -4,14 +4,8 @@ title: Origin
original_id: origin original_id: origin
--- ---
LIGO is a programming language that aims to provide developers with an LIGO is a programming language that aims to provide developers with an uncomplicated and safe way to implement smart contracts. Since it is being implemented for the Tezos blockchain LIGO compiles to Michelson—the native smart contract language of Tezos.
uncomplicated and safe way to implement smart contracts. Since it is
being implemented for the Tezos blockchain LIGO compiles to Michelson,
the native smart contract language of Tezos.
> Smart contracts are programs that run within a blockchain network. > Smart contracts are programs that run within a blockchain network.
LIGO was meant to be a language for developing Marigold on top of a LIGO was meant to be a language for developing Marigold on top of a hacky framework called Meta-Michelson. However, due to the attention received by the Tezos community, LIGO is now a standalone language being developed to support Tezos directly.
hacky framework called Meta-Michelson. However, due to the attention
received by the Tezos community, LIGO is now a standalone language
being developed to support Tezos directly.

View File

@ -4,79 +4,42 @@ title: Philosophy
original_id: philosophy original_id: philosophy
--- ---
To understand LIGOs design choices it is important to understand its To understand LIGOs design choices its important to understand its philosophy. We have two main concerns in mind while building LIGO.
philosophy. We have two main concerns in mind while building LIGO.
## Safety ## Safety
Once a smart contract is deployed, it will likely be impossible to change it. You must get it right on the first try, and LIGO should help as much as possible. There are multiple ways to make LIGO a safer language for smart contracts.
Once a smart contract is deployed, it will likely be impossible to
change it. You must get it right on the first try, and LIGO should
help as much as possible. There are multiple ways to make LIGO a safer
language for smart contracts.
### Automated Testing ### Automated Testing
Automated Testing is the process through which a program runs another program, and checks that this other program behaves correctly.
Automated Testing is the process through which a program runs another There already is a testing library for LIGO programs written in OCaml that is used to test LIGO itself. Making it accessible to users will greatly improve safety. A way to do so would be to make it accessible from within LIGO.
program, and checks that this other program behaves correctly.
There already is a testing library for LIGO programs written in OCaml
that is used to test LIGO itself. Making it accessible to users will
greatly improve safety. A way to do so would be to make it accessible
from within LIGO.
### Static Analysis ### Static Analysis
Static analysis is the process of having a program analyze another one.
Static analysis is the process of having a program analyze another For instance, type systems are a kind of static analysis through which it is possible to find lots of bugs. LIGO already has a simple type system, and we plan to make it much stronger.
one. For instance, type systems are a kind of static analysis through
which it is possible to find lots of bugs. LIGO already has a simple
type system, and we plan to make it much stronger.
### Conciseness ### Conciseness
Writing less code gives you less room to introduce errors. That's why LIGO encourages writing lean rather than chunky smart contracts.
Writing less code gives you less room to introduce errors. That is why
LIGO encourages writing lean rather than chunky smart contracts.
--- ---
## Ergonomics ## Ergonomics
Having an ergonomic product is crucial on multiple levels:
Having an ergonomic product is crucial on multiple levels: Making Making features easily accessible ensures theyll actually get used.
features easily accessible ensures they will actually get used. Not Not wasting users time on idiosyncrasies frees more time for making contracts safer or building apps.
wasting users time on idiosyncrasies frees more time for making Keeping users in a Flow state makes it possible to introduce more complex features in the language.
contracts safer or building apps. Keeping users in a Flow state makes There are multiple ways to improve ergonomics.
it possible to introduce more complex features in the language. There
are multiple ways to improve ergonomics.
### The Language ### The Language
LIGO should contain as few surprises as possible. This is usually known as the principle of least surprise.
LIGO should contain as few surprises as possible. This is usually Most programmers who will use LIGO have already spent a lot of time learning to develop in an existing language, with its own set of conventions and expectations. These expectations are often the most important to accommodate. This is why C-style syntaxes are especially popular (e.g. JavaScript), C-style is well known and new languages want to take advantage of that familiarity. Therefore as an extension of the principle of least surprise, LIGO supports more than one syntax. The least surprising language for a new developer is the one that they have already learned how to use. Its probably not practical to replicate the syntax of every programming language, so LIGO takes the approach of replicating the structure used by languages from a particular paradigm.
known as the principle of least surprise.
Most programmers who will use LIGO have already spent a lot of time It is packaged in a Docker container, so that no particular installation instructions are required.
learning to develop in an existing language, with its own set of
conventions and expectations. These expectations are often the most
important to accommodate. This is why C-style syntaxes are especially
popular (e.g. JavaScript), C-style is well known and new languages
want to take advantage of that familiarity. Therefore as an extension
of the principle of least surprise, LIGO supports more than one
syntax. The least surprising language for a new developer is the one
that they have already learned how to use. Its probably not practical
to replicate the syntax of every programming language, so LIGO takes
the approach of replicating the structure used by languages from a
particular paradigm.
It is packaged in a Docker container, so that no particular
installation instructions are required.
### Editor Support ### Editor Support
Without editor support, a lot of manipulations are very cumbersome. Checking for errors, testing, examining code, refactoring code, etc. This is why there is ongoing work on editor support, starting with highlighting and code-folding.
Without editor support, a lot of manipulations are very ### Docs
cumbersome. Checking for errors, testing, examining code, refactoring Docs include documentation of the languages, tutorials, as well as examples and design patterns.
code, etc. This is why there is ongoing work on editor support, Were a long way from there. But having extensive docs is part of our goals.
starting with highlighting and code-folding.
### Documentation
Documentation includes a reference of the languages, tutorials, as
well as examples and design patterns. We are a long way from
there. But having an extensive documentation is part of our goals.

View File

@ -1,4 +1,3 @@
#!/bin/sh #!/bin/sh
set -e set -e
set -x
docker build -t "${LIGO_REGISTRY_IMAGE_BUILD:-ligolang/ligo}:next" -f ./docker/distribution/debian/distribute.Dockerfile . docker build -t "${LIGO_REGISTRY_IMAGE_BUILD:-ligolang/ligo}:next" -f ./docker/distribution/debian/distribute.Dockerfile .

View File

@ -1,6 +1,5 @@
#!/bin/sh #!/bin/sh
set -e set -e
set -x
eval $(opam config env) eval $(opam config env)
dune build -p ligo dune build -p ligo

View File

@ -1,6 +1,4 @@
#!/bin/sh #!/bin/sh
set -e
set -x
dockerfile_name="build" dockerfile_name="build"
# Generic dockerfile # Generic dockerfile

View File

@ -1,6 +1,4 @@
#!/bin/sh #!/bin/sh
set -e
set -x
dockerfile_name="package" dockerfile_name="package"
dockerfile="" dockerfile=""

View File

@ -1,15 +1,11 @@
#!/bin/sh
set -e
set -x
# This script accepts three arguments, os family, os and its version, # This script accepts three arguments, os family, os and its version,
# which are subsequently used to fetch the respective docker # which are subsequently used to fetch the respective docker
# image from the ocaml/infrastructure project. # image from the ocaml/infrastructure project.
# #
# https://github.com/ocaml/infrastructure/wiki/Containers#selecting-linux-distributions # https://github.com/ocaml/infrastructure/wiki/Containers#selecting-linux-distributions
target_os_family="$1" target_os_family=$1
target_os="$2" target_os=$2
target_os_version="$3" target_os_version=$3
# Variables configured at the CI level # Variables configured at the CI level
dist="$LIGO_DIST_DIR" dist="$LIGO_DIST_DIR"

View File

@ -22,7 +22,6 @@ echo "Installing dependencies.."
if [ -n "`uname -a | grep -i arch`" ] if [ -n "`uname -a | grep -i arch`" ]
then then
sudo pacman -Sy --noconfirm \ sudo pacman -Sy --noconfirm \
python \
make \ make \
m4 \ m4 \
gcc \ gcc \
@ -35,8 +34,6 @@ fi
if [ -n "`uname -a | grep -i ubuntu`" ] if [ -n "`uname -a | grep -i ubuntu`" ]
then then
sudo apt-get install -y make \ sudo apt-get install -y make \
python3 \
make \
m4 \ m4 \
gcc \ gcc \
patch \ patch \

View File

@ -1,13 +1,11 @@
#!/bin/sh #!/bin/sh
set -e set -e
set -x
. /etc/os-release . /etc/os-release
if [ $ID = arch ] if [ $ID = arch ]
then then
pacman -Sy pacman -Sy
sudo pacman -S --noconfirm \ sudo pacman -S --noconfirm \
python \
libevdev \ libevdev \
perl \ perl \
pkg-config \ pkg-config \
@ -22,7 +20,6 @@ then
else else
apt-get update -qq apt-get update -qq
apt-get -y -qq install \ apt-get -y -qq install \
python3 \
libev-dev \ libev-dev \
perl \ perl \
pkg-config \ pkg-config \

View File

@ -1,6 +1,5 @@
#!/bin/sh #!/bin/sh
set -e set -e
set -x
# Install local dependencies # Install local dependencies
opam install -y --deps-only --with-test ./ligo.opam $(find vendors -name \*.opam) opam install -y --deps-only --with-test ./ligo.opam $(find vendors -name \*.opam)

View File

@ -649,6 +649,7 @@ and type_expression' : environment -> ?tv_opt:O.type_expression -> I.expression
let wtype = Format.asprintf let wtype = Format.asprintf
"Loops over collections expect lists, sets or maps, got type %a" O.PP.type_expression tv_col in "Loops over collections expect lists, sets or maps, got type %a" O.PP.type_expression tv_col in
fail @@ simple_error wtype in fail @@ simple_error wtype in
let lname = lname in
let e' = Environment.add_ez_binder lname input_type e in let e' = Environment.add_ez_binder lname input_type e in
let%bind body = type_expression' ?tv_opt:(Some tv_out) e' result in let%bind body = type_expression' ?tv_opt:(Some tv_out) e' result in
let output_type = body.type_expression in let output_type = body.type_expression in

View File

@ -327,6 +327,9 @@ module Typer = struct
let tc_divargs a b c = tc [a;b;c] [ (*TODO…*) ] let tc_divargs a b c = tc [a;b;c] [ (*TODO…*) ]
let tc_modargs a b c = tc [a;b;c] [ (*TODO…*) ] let tc_modargs a b c = tc [a;b;c] [ (*TODO…*) ]
let tc_addargs a b c = tc [a;b;c] [ (*TODO…*) ] let tc_addargs a b c = tc [a;b;c] [ (*TODO…*) ]
let tc_comparable a = tc [a] [ [nat] ; [int] ; [mutez] ; [timestamp] ]
let tc_concatable a = tc [a] [ [string] ; [bytes] ]
let tc_storable a = tc [a] [ [string] ; [bytes] ; (*Humm .. TODO ?*) ]
let t_none = forall "a" @@ fun a -> option a let t_none = forall "a" @@ fun a -> option a
@ -355,18 +358,20 @@ module Typer = struct
let t_hash512 = tuple1 bytes --> bytes let t_hash512 = tuple1 bytes --> bytes
let t_blake2b = tuple1 bytes --> bytes let t_blake2b = tuple1 bytes --> bytes
let t_hash_key = tuple1 key --> key_hash let t_hash_key = tuple1 key --> key_hash
let t_is_nat = tuple1 int --> bool
let t_check_signature = tuple3 key signature bytes --> bool let t_check_signature = tuple3 key signature bytes --> bool
let t_chain_id = tuple0 --> chain_id let t_chain_id = tuple0 --> chain_id
let t_sender = tuple0 --> address let t_sender = tuple0 --> address
let t_source = tuple0 --> address let t_source = tuple0 --> address
let t_unit = tuple0 --> unit let t_unit = tuple0 --> unit
let t_amount = tuple0 --> mutez let t_amount = tuple0 --> mutez
let t_balance = tuple0 --> mutez
let t_address = tuple0 --> address let t_address = tuple0 --> address
let t_now = tuple0 --> timestamp let t_now = tuple0 --> timestamp
let t_transaction = forall "a" @@ fun a -> tuple3 a mutez (contract a) --> operation let t_transaction = forall "a" @@ fun a -> tuple3 a mutez (contract a) --> operation
let t_get_contract = forall "a" @@ fun a -> tuple0 --> contract a let t_get_contract = forall "a" @@ fun a -> tuple0 --> contract a
let t_abs = tuple1 int --> nat let t_abs = tuple1 int --> nat
let t_cons = forall "a" @@ fun a -> a --> tuple1 (list a) --> list a let t_cons = forall "a" @@ fun a -> tuple2 a (list a) --> list a
let t_assertion = tuple1 bool --> unit let t_assertion = tuple1 bool --> unit
let t_times = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_timargs a b c] => tuple2 a b --> c (* TYPECLASS *) let t_times = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_timargs a b c] => tuple2 a b --> c (* TYPECLASS *)
let t_div = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_divargs a b c] => tuple2 a b --> c (* TYPECLASS *) let t_div = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_divargs a b c] => tuple2 a b --> c (* TYPECLASS *)
@ -377,21 +382,43 @@ module Typer = struct
let t_set_remove = forall "a" @@ fun a -> tuple2 a (set a) --> set a let t_set_remove = forall "a" @@ fun a -> tuple2 a (set a) --> set a
let t_not = tuple1 bool --> bool let t_not = tuple1 bool --> bool
let t_continuation = forall "a" @@ fun a -> tuple2 bool a --> pair bool a
let t_fold_while = forall "a" @@ fun a -> tuple2 (a --> pair bool a) a --> a
let t_neg = tuple1 int --> int
let t_and = tuple2 bool bool --> bool
let t_or = tuple2 bool bool --> bool
let t_xor = tuple2 bool bool --> bool
let t_lsl = tuple2 nat nat --> nat
let t_lsr = tuple2 nat nat --> nat
let t_comp = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 a a --> bool
let t_concat = forall_tc "a" @@ fun a -> [tc_concatable a] => tuple2 a a --> a
let t_set_empty = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple0 --> set a
let t_set_iter = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 (a --> unit) (set a) --> unit
(* TODO: check that the implementation has this type *)
let t_set_fold = forall2_tc "a" "b" @@ fun a b -> [tc_comparable b] => tuple3 (pair a b --> a) (set b) a --> a
let t_list_iter = forall "a" @@ fun a -> tuple2 (a --> unit) (list a) --> unit
let t_list_map = forall "a" @@ fun a -> tuple2 (a --> a) (list a) --> (list a)
(* TODO: check that the implementation has this type *)
let t_list_fold = forall2 "a" "b" @@ fun a b -> tuple3 (pair a b --> a) (list b) a --> a
let t_self_address = tuple0 --> address
let t_implicit_account = forall_tc "a" @@ fun a -> [tc_storable a] => tuple1 key_hash --> contract a
let t_set_delegate = tuple1 (option key_hash) --> operation
let constant_type : constant' -> Typesystem.Core.type_value result = function let constant_type : constant' -> Typesystem.Core.type_value result = function
| C_INT -> ok @@ t_int ; | C_INT -> ok @@ t_int ;
| C_UNIT -> ok @@ t_unit ; | C_UNIT -> ok @@ t_unit ;
| C_NOW -> ok @@ t_now ; | C_NOW -> ok @@ t_now ;
| C_IS_NAT -> ok @@ failwith "t_is_nat" ; | C_IS_NAT -> ok @@ t_is_nat ;
| C_SOME -> ok @@ t_some ; | C_SOME -> ok @@ t_some ;
| C_NONE -> ok @@ t_none ; | C_NONE -> ok @@ t_none ;
| C_ASSERTION -> ok @@ t_assertion ; | C_ASSERTION -> ok @@ t_assertion ;
| C_FAILWITH -> ok @@ t_failwith ; | C_FAILWITH -> ok @@ t_failwith ;
(* LOOPS *) (* LOOPS *)
| C_FOLD_WHILE -> ok @@ failwith "t_fold_while" ; | C_FOLD_WHILE -> ok @@ t_fold_while ;
| C_CONTINUE -> ok @@ failwith "t_continue" ; | C_CONTINUE -> ok @@ t_continuation ;
| C_STOP -> ok @@ failwith "t_stop" ; | C_STOP -> ok @@ t_continuation ;
(* MATH *) (* MATH *)
| C_NEG -> ok @@ failwith "t_neg" ; | C_NEG -> ok @@ t_neg ;
| C_ABS -> ok @@ t_abs ; | C_ABS -> ok @@ t_abs ;
| C_ADD -> ok @@ t_add ; | C_ADD -> ok @@ t_add ;
| C_SUB -> ok @@ t_sub ; | C_SUB -> ok @@ t_sub ;
@ -400,38 +427,38 @@ module Typer = struct
| C_MOD -> ok @@ t_mod ; | C_MOD -> ok @@ t_mod ;
(* LOGIC *) (* LOGIC *)
| C_NOT -> ok @@ t_not ; | C_NOT -> ok @@ t_not ;
| C_AND -> ok @@ failwith "t_and" ; | C_AND -> ok @@ t_and ;
| C_OR -> ok @@ failwith "t_or" ; | C_OR -> ok @@ t_or ;
| C_XOR -> ok @@ failwith "t_xor" ; | C_XOR -> ok @@ t_xor ;
| C_LSL -> ok @@ failwith "t_lsl" ; | C_LSL -> ok @@ t_lsl ;
| C_LSR -> ok @@ failwith "t_lsr" ; | C_LSR -> ok @@ t_lsr ;
(* COMPARATOR *) (* COMPARATOR *)
| C_EQ -> ok @@ failwith "t_comparator EQ" ; | C_EQ -> ok @@ t_comp ;
| C_NEQ -> ok @@ failwith "t_comparator NEQ" ; | C_NEQ -> ok @@ t_comp ;
| C_LT -> ok @@ failwith "t_comparator LT" ; | C_LT -> ok @@ t_comp ;
| C_GT -> ok @@ failwith "t_comparator GT" ; | C_GT -> ok @@ t_comp ;
| C_LE -> ok @@ failwith "t_comparator LE" ; | C_LE -> ok @@ t_comp ;
| C_GE -> ok @@ failwith "t_comparator GE" ; | C_GE -> ok @@ t_comp ;
(* BYTES / STRING *) (* BYTES / STRING *)
| C_SIZE -> ok @@ t_size ; | C_SIZE -> ok @@ t_size ;
| C_CONCAT -> ok @@ failwith "t_concat" ; | C_CONCAT -> ok @@ t_concat ;
| C_SLICE -> ok @@ t_slice ; | C_SLICE -> ok @@ t_slice ;
| C_BYTES_PACK -> ok @@ t_bytes_pack ; | C_BYTES_PACK -> ok @@ t_bytes_pack ;
| C_BYTES_UNPACK -> ok @@ t_bytes_unpack ; | C_BYTES_UNPACK -> ok @@ t_bytes_unpack ;
| C_CONS -> ok @@ t_cons ; | C_CONS -> ok @@ t_cons ;
(* SET *) (* SET *)
| C_SET_EMPTY -> ok @@ failwith "t_set_empty" ; | C_SET_EMPTY -> ok @@ t_set_empty ;
| C_SET_ADD -> ok @@ t_set_add ; | C_SET_ADD -> ok @@ t_set_add ;
| C_SET_REMOVE -> ok @@ t_set_remove ; | C_SET_REMOVE -> ok @@ t_set_remove ;
| C_SET_ITER -> ok @@ failwith "t_set_iter" ; | C_SET_ITER -> ok @@ t_set_iter ;
| C_SET_FOLD -> ok @@ failwith "t_set_fold" ; | C_SET_FOLD -> ok @@ t_set_fold ;
| C_SET_MEM -> ok @@ t_set_mem ; | C_SET_MEM -> ok @@ t_set_mem ;
(* LIST *) (* LIST *)
| C_LIST_ITER -> ok @@ failwith "t_list_iter" ; | C_LIST_ITER -> ok @@ t_list_iter ;
| C_LIST_MAP -> ok @@ failwith "t_list_map" ; | C_LIST_MAP -> ok @@ t_list_map ;
| C_LIST_FOLD -> ok @@ failwith "t_list_fold" ; | C_LIST_FOLD -> ok @@ t_list_fold ;
| C_LIST_CONS -> ok @@ failwith "t_list_cons" ;
(* MAP *) (* MAP *)
| C_MAP_ADD -> ok @@ t_map_add ; | C_MAP_ADD -> ok @@ t_map_add ;
| C_MAP_REMOVE -> ok @@ t_map_remove ; | C_MAP_REMOVE -> ok @@ t_map_remove ;
@ -454,14 +481,14 @@ module Typer = struct
| C_CONTRACT -> ok @@ t_get_contract ; | C_CONTRACT -> ok @@ t_get_contract ;
| C_CONTRACT_ENTRYPOINT -> ok @@ failwith "t_get_entrypoint" ; | C_CONTRACT_ENTRYPOINT -> ok @@ failwith "t_get_entrypoint" ;
| C_AMOUNT -> ok @@ t_amount ; | C_AMOUNT -> ok @@ t_amount ;
| C_BALANCE -> ok @@ failwith "t_balance" ; | C_BALANCE -> ok @@ t_balance ;
| C_CALL -> ok @@ t_transaction ; | C_CALL -> ok @@ t_transaction ;
| C_SENDER -> ok @@ t_sender ; | C_SENDER -> ok @@ t_sender ;
| C_SOURCE -> ok @@ t_source ; | C_SOURCE -> ok @@ t_source ;
| C_ADDRESS -> ok @@ t_address ; | C_ADDRESS -> ok @@ t_address ;
| C_SELF_ADDRESS -> ok @@ failwith "t_self_address"; | C_SELF_ADDRESS -> ok @@ t_self_address;
| C_IMPLICIT_ACCOUNT -> ok @@ failwith "t_implicit_account"; | C_IMPLICIT_ACCOUNT -> ok @@ t_implicit_account;
| C_SET_DELEGATE -> ok @@ failwith "t_set_delegate" ; | C_SET_DELEGATE -> ok @@ t_set_delegate ;
| c -> simple_fail @@ Format.asprintf "Typer not implemented for consant %a" Stage_common.PP.constant c | c -> simple_fail @@ Format.asprintf "Typer not implemented for consant %a" Stage_common.PP.constant c
end end
@ -489,11 +516,6 @@ module Typer = struct
let some = typer_1 "SOME" @@ fun a -> ok @@ t_option a () let some = typer_1 "SOME" @@ fun a -> ok @@ t_option a ()
let list_cons : typer = typer_2 "CONS" @@ fun hd tl ->
let%bind tl' = get_t_list tl in
let%bind () = assert_type_expression_eq (hd , tl') in
ok tl
let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m -> let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m ->
let%bind (src , _) = bind_map_or (get_t_map , get_t_big_map) m in let%bind (src , _) = bind_map_or (get_t_map , get_t_big_map) m in
let%bind () = assert_type_expression_eq (src , k) in let%bind () = assert_type_expression_eq (src , k) in
@ -1031,7 +1053,6 @@ module Typer = struct
| C_LIST_ITER -> ok @@ list_iter ; | C_LIST_ITER -> ok @@ list_iter ;
| C_LIST_MAP -> ok @@ list_map ; | C_LIST_MAP -> ok @@ list_map ;
| C_LIST_FOLD -> ok @@ list_fold ; | C_LIST_FOLD -> ok @@ list_fold ;
| C_LIST_CONS -> ok @@ list_cons ;
(* MAP *) (* MAP *)
| C_MAP_ADD -> ok @@ map_add ; | C_MAP_ADD -> ok @@ map_add ;
| C_MAP_REMOVE -> ok @@ map_remove ; | C_MAP_REMOVE -> ok @@ map_remove ;

View File

@ -1,2 +0,0 @@
# This is an auto-generated test file
/generated_fold.ml

View File

@ -1,6 +1,6 @@
Build & test with: Build with:
dune build adt_generator.exe && ../../../_build/default/src/stages/adt_generator/adt_generator.exe dune build adt_generator.a
Run with Run with

View File

@ -1,6 +1,6 @@
type root = type root =
| A of rootA | A of a
| B of rootB | B of int
| C of string | C of string
and a = { and a = {
@ -15,20 +15,3 @@ and ta1 =
and ta2 = and ta2 =
| Z of ta2 | Z of ta2
| W of unit | W of unit
and rootA =
a list
and rootB =
int list
let fold_list v state continue =
let aux = fun (lst', state) elt ->
let (elt', state) = continue elt state in
(elt' :: lst' , state) in
List.fold_left aux ([], state) v
let fold_option v state continue =
match v with
Some x -> continue x state
| None -> None

View File

@ -1,9 +1,8 @@
(rule (rule
(target generated_fold.ml) (target fold.ml)
(deps generator.py) (deps generator.py)
(action (with-stdout-to generated_fold.ml (run python3 ./generator.py))) (action (with-stdout-to fold.ml (run python3 ./generator.py)))
; (mode (promote (until-clean))) ; If this is uncommented, then "dune build -p ligo" can't find the file (but "dune build" can) (mode (promote (until-clean))))
)
; (library ; (library
; (name adt_generator) ; (name adt_generator)
; (public_name ligo.adt_generator) ; (public_name ligo.adt_generator)
@ -17,8 +16,3 @@
(libraries (libraries
) )
) )
(alias
(name runtest)
(action (run ./adt_generator.exe))
)

View File

@ -1 +1,184 @@
include Generated_fold open A
type root' =
| A' of a'
| B' of int
| C' of string
and a' =
{
a1' : ta1' ;
a2' : ta2' ;
}
and ta1' =
| X' of root'
| Y' of ta2'
and ta2' =
| Z' of ta2'
| W' of unit
type 'state continue_fold =
{
root : root -> 'state -> (root' * 'state) ;
root_A : a -> 'state -> (a' * 'state) ;
root_B : int -> 'state -> (int * 'state) ;
root_C : string -> 'state -> (string * 'state) ;
a : a -> 'state -> (a' * 'state) ;
a_a1 : ta1 -> 'state -> (ta1' * 'state) ;
a_a2 : ta2 -> 'state -> (ta2' * 'state) ;
ta1 : ta1 -> 'state -> (ta1' * 'state) ;
ta1_X : root -> 'state -> (root' * 'state) ;
ta1_Y : ta2 -> 'state -> (ta2' * 'state) ;
ta2 : ta2 -> 'state -> (ta2' * 'state) ;
ta2_Z : ta2 -> 'state -> (ta2' * 'state) ;
ta2_W : unit -> 'state -> (unit * 'state) ;
}
type 'state fold_config =
{
root : root -> 'state -> ('state continue_fold) -> (root' * 'state) ;
root_pre_state : root -> 'state -> 'state ;
root_post_state : root -> root' -> 'state -> 'state ;
root_A : a -> 'state -> ('state continue_fold) -> (a' * 'state) ;
root_B : int -> 'state -> ('state continue_fold) -> (int * 'state) ;
root_C : string -> 'state -> ('state continue_fold) -> (string * 'state) ;
a : a -> 'state -> ('state continue_fold) -> (a' * 'state) ;
a_pre_state : a -> 'state -> 'state ;
a_post_state : a -> a' -> 'state -> 'state ;
a_a1 : ta1 -> 'state -> ('state continue_fold) -> (ta1' * 'state) ;
a_a2 : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ;
ta1 : ta1 -> 'state -> ('state continue_fold) -> (ta1' * 'state) ;
ta1_pre_state : ta1 -> 'state -> 'state ;
ta1_post_state : ta1 -> ta1' -> 'state -> 'state ;
ta1_X : root -> 'state -> ('state continue_fold) -> (root' * 'state) ;
ta1_Y : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ;
ta2 : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ;
ta2_pre_state : ta2 -> 'state -> 'state ;
ta2_post_state : ta2 -> ta2' -> 'state -> 'state ;
ta2_Z : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ;
ta2_W : unit -> 'state -> ('state continue_fold) -> (unit * 'state) ;
}
(* Curries the "visitor" argument to the folds (non-customizable traversal functions). *)
let rec mk_continue_fold : type state . state fold_config -> state continue_fold = fun visitor ->
{
root = fold_root visitor ;
root_A = fold_root_A visitor ;
root_B = fold_root_B visitor ;
root_C = fold_root_C visitor ;
a = fold_a visitor ;
a_a1 = fold_a_a1 visitor ;
a_a2 = fold_a_a2 visitor ;
ta1 = fold_ta1 visitor ;
ta1_X = fold_ta1_X visitor ;
ta1_Y = fold_ta1_Y visitor ;
ta2 = fold_ta2 visitor ;
ta2_Z = fold_ta2_Z visitor ;
ta2_W = fold_ta2_W visitor ;
}
and fold_root : type state . state fold_config -> root -> state -> (root' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
let state = visitor.root_pre_state x state in
let (new_x, state) = visitor.root x state continue_fold in
let state = visitor.root_post_state x new_x state in
(new_x, state)
and fold_root_A : type state . state fold_config -> a -> state -> (a' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.root_A x state continue_fold
and fold_root_B : type state . state fold_config -> int -> state -> (int * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.root_B x state continue_fold
and fold_root_C : type state . state fold_config -> string -> state -> (string * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.root_C x state continue_fold
and fold_a : type state . state fold_config -> a -> state -> (a' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
let state = visitor.a_pre_state x state in
let (new_x, state) = visitor.a x state continue_fold in
let state = visitor.a_post_state x new_x state in
(new_x, state)
and fold_a_a1 : type state . state fold_config -> ta1 -> state -> (ta1' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.a_a1 x state continue_fold
and fold_a_a2 : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.a_a2 x state continue_fold
and fold_ta1 : type state . state fold_config -> ta1 -> state -> (ta1' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
let state = visitor.ta1_pre_state x state in
let (new_x, state) = visitor.ta1 x state continue_fold in
let state = visitor.ta1_post_state x new_x state in
(new_x, state)
and fold_ta1_X : type state . state fold_config -> root -> state -> (root' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.ta1_X x state continue_fold
and fold_ta1_Y : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.ta1_Y x state continue_fold
and fold_ta2 : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
let state = visitor.ta2_pre_state x state in
let (new_x, state) = visitor.ta2 x state continue_fold in
let state = visitor.ta2_post_state x new_x state in
(new_x, state)
and fold_ta2_Z : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.ta2_Z x state continue_fold
and fold_ta2_W : type state . state fold_config -> unit -> state -> (unit * state) = fun visitor x state ->
let continue_fold : state continue_fold = mk_continue_fold visitor in
visitor.ta2_W x state continue_fold
let no_op : 'a fold_config = {
root = (fun v state continue ->
match v with
| A v -> let (v, state) = continue.root_A v state in (A' v, state)
| B v -> let (v, state) = continue.root_B v state in (B' v, state)
| C v -> let (v, state) = continue.root_C v state in (C' v, state)
);
root_pre_state = (fun v state -> ignore v; state) ;
root_post_state = (fun v new_v state -> ignore (v, new_v); state) ;
root_A = (fun v state continue -> continue.a v state ) ;
root_B = (fun v state continue -> ignore continue; (v, state) ) ;
root_C = (fun v state continue -> ignore continue; (v, state) ) ;
a = (fun v state continue ->
match v with
{ a1; a2; } ->
let (a1', state) = continue.a_a1 a1 state in
let (a2', state) = continue.a_a2 a2 state in
({ a1'; a2'; }, state)
);
a_pre_state = (fun v state -> ignore v; state) ;
a_post_state = (fun v new_v state -> ignore (v, new_v); state) ;
a_a1 = (fun v state continue -> continue.ta1 v state ) ;
a_a2 = (fun v state continue -> continue.ta2 v state ) ;
ta1 = (fun v state continue ->
match v with
| X v -> let (v, state) = continue.ta1_X v state in (X' v, state)
| Y v -> let (v, state) = continue.ta1_Y v state in (Y' v, state)
);
ta1_pre_state = (fun v state -> ignore v; state) ;
ta1_post_state = (fun v new_v state -> ignore (v, new_v); state) ;
ta1_X = (fun v state continue -> continue.root v state ) ;
ta1_Y = (fun v state continue -> continue.ta2 v state ) ;
ta2 = (fun v state continue ->
match v with
| Z v -> let (v, state) = continue.ta2_Z v state in (Z' v, state)
| W v -> let (v, state) = continue.ta2_W v state in (W' v, state)
);
ta2_pre_state = (fun v state -> ignore v; state) ;
ta2_post_state = (fun v new_v state -> ignore (v, new_v); state) ;
ta2_Z = (fun v state continue -> continue.ta2 v state ) ;
ta2_W = (fun v state continue -> ignore continue; (v, state) ) ;
}

View File

@ -1,49 +1,34 @@
moduleName = "A" moduleName = "A"
variant="_ _variant"
record="_ _record"
def poly(x): return x
adts = [ adts = [
# typename, kind, fields_or_ctors # typename, variant?, fields_or_ctors
("root", variant, [ ("root", True, [
# ctor, builtin?, type # ctor, builtin, type
("A", False, "rootA"), ("A", False, "a"),
("B", False, "rootB"), ("B", True, "int"),
("C", True, "string"), ("C", True, "string"),
]), ]),
("a", record, [ ("a", False, [
# field, builtin?, type
("a1", False, "ta1"), ("a1", False, "ta1"),
("a2", False, "ta2"), ("a2", False, "ta2"),
]), ]),
("ta1", variant, [ ("ta1", True, [
("X", False, "root"), ("X", False, "root"),
("Y", False, "ta2"), ("Y", False, "ta2"),
]), ]),
("ta2", variant, [ ("ta2", True, [
("Z", False, "ta2"), ("Z", False, "ta2"),
("W", True, "unit"), ("W", True, "unit"),
]), ]),
# polymorphic type
("rootA", poly("list"),
[
# Position (0..n-1), builtin?, type argument
(0, False, "a")
]),
("rootB", poly("list"),
[
# Position (0..n-1), builtin?, type argument
(0, True, "int")
]),
] ]
from collections import namedtuple from collections import namedtuple
adt = namedtuple('adt', ['name', 'newName', 'kind', 'ctorsOrFields']) adt = namedtuple('adt', ['name', 'newName', 'isVariant', 'ctorsOrFields'])
ctorOrField = namedtuple('ctorOrField', ['name', 'newName', 'isBuiltin', 'type_', 'newType']) ctorOrField = namedtuple('ctorOrField', ['name', 'newName', 'isBuiltin', 'type_', 'newType'])
adts = [ adts = [
adt( adt(
name = name, name = name,
newName = f"{name}'", newName = f"{name}'",
kind = kind, isVariant = isVariant,
ctorsOrFields = [ ctorsOrFields = [
ctorOrField( ctorOrField(
name = cf, name = cf,
@ -55,32 +40,23 @@ adts = [
for (cf, isBuiltin, type_) in ctors for (cf, isBuiltin, type_) in ctors
], ],
) )
for (name, kind, ctors) in adts for (name, isVariant, ctors) in adts
] ]
print("(* This is an auto-generated file. Do not edit. *)")
print("")
print("open %s" % moduleName) print("open %s" % moduleName)
print("") print("")
for (index, t) in enumerate(adts): for (index, t) in enumerate(adts):
typeOrAnd = "type" if index == 0 else "and" typeOrAnd = "type" if index == 0 else "and"
print(f"{typeOrAnd} {t.newName} =") print(f"{typeOrAnd} {t.newName} =")
if t.kind == variant: if t.isVariant:
for c in t.ctorsOrFields: for c in t.ctorsOrFields:
print(f" | {c.newName} of {c.newType}") print(f" | {c.newName} of {c.newType}")
elif t.kind == record: else:
print(" {") print(" {")
for f in t.ctorsOrFields: for f in t.ctorsOrFields:
print(f" {f.newName} : {f.newType} ;") print(f" {f.newName} : {f.newType} ;")
print(" }") print(" }")
else:
print(" ", end='')
for a in t.ctorsOrFields:
print(f"{a.newType}", end=' ')
print(t.kind, end='')
print("")
print("") print("")
print(f"type 'state continue_fold =") print(f"type 'state continue_fold =")
@ -131,10 +107,10 @@ print("let no_op : 'a fold_config = {")
for t in adts: for t in adts:
print(f" {t.name} = (fun v state continue ->") print(f" {t.name} = (fun v state continue ->")
print(" match v with") print(" match v with")
if t.kind == variant: if t.isVariant:
for c in t.ctorsOrFields: for c in t.ctorsOrFields:
print(f" | {c.name} v -> let (v, state) = continue.{t.name}_{c.name} v state in ({c.newName} v, state)") print(f" | {c.name} v -> let (v, state) = continue.{t.name}_{c.name} v state in ({c.newName} v, state)")
elif t.kind == record: else:
print(" {", end=' ') print(" {", end=' ')
for f in t.ctorsOrFields: for f in t.ctorsOrFields:
print(f"{f.name};", end=' ') print(f"{f.name};", end=' ')
@ -145,10 +121,6 @@ for t in adts:
for f in t.ctorsOrFields: for f in t.ctorsOrFields:
print(f"{f.newName};", end=' ') print(f"{f.newName};", end=' ')
print("}, state)") print("}, state)")
else:
print(f" v -> fold_{t.kind} v state (", end=' ')
print(", ".join([f"continue.{t.name}_{f.name}" for f in t.ctorsOrFields]), end='')
print(" )")
print(" );") print(" );")
print(f" {t.name}_pre_state = (fun v state -> ignore v; state) ;") print(f" {t.name}_pre_state = (fun v state -> ignore v; state) ;")
print(f" {t.name}_post_state = (fun v new_v state -> ignore (v, new_v); state) ;") print(f" {t.name}_post_state = (fun v new_v state -> ignore (v, new_v); state) ;")

View File

@ -4,7 +4,7 @@ open Fold
(* TODO: how should we plug these into our test framework? *) (* TODO: how should we plug these into our test framework? *)
let () = let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in
let op = { let op = {
no_op with no_op with
a = fun the_a state continue_fold -> a = fun the_a state continue_fold ->
@ -23,7 +23,7 @@ let () =
() ()
let () = let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in
let op = { no_op with a_pre_state = fun _the_a state -> state + 1 } in let op = { no_op with a_pre_state = fun _the_a state -> state + 1 } in
let state = 0 in let state = 0 in
let (_, state) = fold_root op some_root state in let (_, state) = fold_root op some_root state in
@ -33,7 +33,7 @@ let () =
() ()
let () = let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in
let op = { no_op with a_post_state = fun _the_a _new_a state -> state + 1 } in let op = { no_op with a_post_state = fun _the_a _new_a state -> state + 1 } in
let state = 0 in let state = 0 in
let (_, state) = fold_root op some_root state in let (_, state) = fold_root op some_root state in

View File

@ -95,6 +95,7 @@ and matching =
and ascription = {anno_expr: expression; type_annotation: type_expression} and ascription = {anno_expr: expression; type_annotation: type_expression}
and environment_element_definition = and environment_element_definition =
| ED_binder | ED_binder
| ED_declaration of (expression * free_variables) | ED_declaration of (expression * free_variables)

View File

@ -105,7 +105,6 @@ let constant ppf : constant' -> unit = function
| C_LIST_ITER -> fprintf ppf "LIST_ITER" | C_LIST_ITER -> fprintf ppf "LIST_ITER"
| C_LIST_MAP -> fprintf ppf "LIST_MAP" | C_LIST_MAP -> fprintf ppf "LIST_MAP"
| C_LIST_FOLD -> fprintf ppf "LIST_FOLD" | C_LIST_FOLD -> fprintf ppf "LIST_FOLD"
| C_LIST_CONS -> fprintf ppf "LIST_CONS"
(* Maps *) (* Maps *)
| C_MAP -> fprintf ppf "MAP" | C_MAP -> fprintf ppf "MAP"
| C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY" | C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY"

View File

@ -247,7 +247,6 @@ and constant' =
| C_LIST_ITER | C_LIST_ITER
| C_LIST_MAP | C_LIST_MAP
| C_LIST_FOLD | C_LIST_FOLD
| C_LIST_CONS
(* Maps *) (* Maps *)
| C_MAP | C_MAP
| C_MAP_EMPTY | C_MAP_EMPTY

View File

@ -201,7 +201,6 @@ and constant ppf : constant' -> unit = function
| C_LIST_ITER -> fprintf ppf "LIST_ITER" | C_LIST_ITER -> fprintf ppf "LIST_ITER"
| C_LIST_MAP -> fprintf ppf "LIST_MAP" | C_LIST_MAP -> fprintf ppf "LIST_MAP"
| C_LIST_FOLD -> fprintf ppf "LIST_FOLD" | C_LIST_FOLD -> fprintf ppf "LIST_FOLD"
| C_LIST_CONS -> fprintf ppf "LIST_CONS"
(* Maps *) (* Maps *)
| C_MAP -> fprintf ppf "MAP" | C_MAP -> fprintf ppf "MAP"
| C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY" | C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY"

View File

@ -39,6 +39,11 @@ let forall3_tc a b c f =
forall_tc c @@ fun c' -> forall_tc c @@ fun c' ->
f a' b' c' f a' b' c'
let forall2_tc a b f =
forall a @@ fun a' ->
forall_tc b @@ fun b' ->
f a' b'
let (=>) tc ty = (tc , ty) let (=>) tc ty = (tc , ty)
let (-->) arg ret = P_constant (C_arrow , [arg; ret]) let (-->) arg ret = P_constant (C_arrow , [arg; ret])
let option t = P_constant (C_option , [t]) let option t = P_constant (C_option , [t])

View File

@ -16,6 +16,8 @@ function set_ (var n : int; var m : foo) : foo is block {
m[23] := n m[23] := n
} with m } with m
function add (var n : int ; var m : foo) : foo is set_(n,m)
function rm (var m : foo) : foo is block { function rm (var m : foo) : foo is block {
remove 42 from map m remove 42 from map m
} with m } with m

View File

@ -1,8 +1,8 @@
type foo = (int, int) big_map type foo = (int, int) big_map
let set_2 (n : int) (m : foo) : foo = Big_map.update 23 (Some n) m let set_ (n, m: int * foo) : foo = Big_map.update 23 (Some n) m
let set_ (t: int * foo) : foo = set_2 t.0 t.1 let add (n,m : int * foo) : foo = Big_map.add 23 n m
let rm (m : foo) : foo = Big_map.remove 42 m let rm (m : foo) : foo = Big_map.remove 42 m

View File

@ -4,6 +4,8 @@ let set2 = (n: int, m: foo): foo => Big_map.update(23, Some(n), m);
let set_ = (x: (int, foo)): foo => set2(x[0], x[1]); let set_ = (x: (int, foo)): foo => set2(x[0], x[1]);
let add = ((n,m): (int, foo)): foo => Big_map.add(23, n, m);
let rm = (m: foo): foo => Big_map.remove(42, m); let rm = (m: foo): foo => Big_map.remove(42, m);
let gf = (m: foo): int => Big_map.find(23, m); let gf = (m: foo): int => Big_map.find(23, m);

View File

@ -1,5 +1,8 @@
(* Test set operations in CameLIGO *) (* Test set operations in CameLIGO *)
let literal_op (p: unit) : string set =
Set.literal ["foo"; "bar"; "foobar"]
let add_op (s : string set) : string set = let add_op (s : string set) : string set =
Set.add "foobar" s Set.add "foobar" s

View File

@ -1,5 +1,7 @@
/* Test set operations in ReasonLIGO */ /* Test set operations in ReasonLIGO */
let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]);
let add_op = (s: set(string)): set(string) => Set.add("foobar", s); let add_op = (s: set(string)): set(string) => Set.add("foobar", s);
let remove_op = (s: set(string)): set(string) => Set.remove("foobar", s); let remove_op = (s: set(string)): set(string) => Set.remove("foobar", s);

View File

@ -582,6 +582,11 @@ let set_arithmetic () : unit result =
let set_arithmetic_mligo () : unit result = let set_arithmetic_mligo () : unit result =
let%bind program = mtype_file "./contracts/set_arithmetic.mligo" in let%bind program = mtype_file "./contracts/set_arithmetic.mligo" in
let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in
let%bind () =
expect_eq program "literal_op"
(e_unit ())
(e_set [e_string "foo"; e_string "bar"; e_string "foobar"])
in
let%bind () = let%bind () =
expect_eq program "size_op" expect_eq program "size_op"
(e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) (e_set [e_string "foo"; e_string "bar"; e_string "foobar"])
@ -612,6 +617,11 @@ let set_arithmetic_mligo () : unit result =
let set_arithmetic_religo () : unit result = let set_arithmetic_religo () : unit result =
let%bind program = retype_file "./contracts/set_arithmetic.religo" in let%bind program = retype_file "./contracts/set_arithmetic.religo" in
let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in
let%bind () =
expect_eq program "literal_op"
(e_unit ())
(e_set [e_string "foo"; e_string "bar"; e_string "foobar"])
in
let%bind () = let%bind () =
expect_eq program "size_op" expect_eq program "size_op"
(e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) (e_set [e_string "foo"; e_string "bar"; e_string "foobar"])
@ -1084,6 +1094,11 @@ let big_map_ type_f path : unit result =
let make_expected = fun n -> ez [(23 , n) ; (42 , 0)] in let make_expected = fun n -> ez [(23 , n) ; (42 , 0)] in
expect_eq_n_pos_small program "set_" make_input make_expected expect_eq_n_pos_small program "set_" make_input make_expected
in in
let%bind () =
let input = (e_pair (e_int 23) (ez [(42, 42)])) in
let expected = ez [(23, 23) ; (42, 42)] in
expect_eq program "add" input expected
in
let%bind () = let%bind () =
let make_input = fun n -> ez [(23, n) ; (42, 4)] in let make_input = fun n -> ez [(23, n) ; (42, 4)] in
let make_expected = fun _ -> e_some @@ e_int 4 in let make_expected = fun _ -> e_some @@ e_int 4 in

View File

@ -123,6 +123,8 @@ let md_files = [
"/gitlab-pages/docs/api/cli-commands.md"; "/gitlab-pages/docs/api/cli-commands.md";
"/gitlab-pages/docs/api/cheat-sheet.md"; "/gitlab-pages/docs/api/cheat-sheet.md";
"/gitlab-pages/docs/reference/map.md"; "/gitlab-pages/docs/reference/map.md";
"/gitlab-pages/docs/reference/set.md";
"/gitlab-pages/docs/reference/big_map.md";
"/gitlab-pages/docs/reference/string.md"; "/gitlab-pages/docs/reference/string.md";
] ]

View File

@ -17,7 +17,7 @@ FROM node:12-buster
WORKDIR /app WORKDIR /app
RUN apt-get update && apt-get -y install python3 libev-dev perl pkg-config libgmp-dev libhidapi-dev m4 libcap-dev bubblewrap rsync RUN apt-get update && apt-get -y install libev-dev perl pkg-config libgmp-dev libhidapi-dev m4 libcap-dev bubblewrap rsync
COPY ligo_deb10.deb /tmp/ligo_deb10.deb COPY ligo_deb10.deb /tmp/ligo_deb10.deb
RUN dpkg -i /tmp/ligo_deb10.deb && rm /tmp/ligo_deb10.deb RUN dpkg -i /tmp/ligo_deb10.deb && rm /tmp/ligo_deb10.deb

36
vendors/UnionFind/UnionFind.install vendored Normal file
View File

@ -0,0 +1,36 @@
lib: [
"_build/install/default/lib/UnionFind/META"
"_build/install/default/lib/UnionFind/Partition.cmi"
"_build/install/default/lib/UnionFind/Partition.cmti"
"_build/install/default/lib/UnionFind/Partition.mli"
"_build/install/default/lib/UnionFind/Partition0.cmi"
"_build/install/default/lib/UnionFind/Partition0.cmt"
"_build/install/default/lib/UnionFind/Partition0.cmx"
"_build/install/default/lib/UnionFind/Partition0.ml"
"_build/install/default/lib/UnionFind/Partition1.cmi"
"_build/install/default/lib/UnionFind/Partition1.cmt"
"_build/install/default/lib/UnionFind/Partition1.cmx"
"_build/install/default/lib/UnionFind/Partition1.ml"
"_build/install/default/lib/UnionFind/Partition2.cmi"
"_build/install/default/lib/UnionFind/Partition2.cmt"
"_build/install/default/lib/UnionFind/Partition2.cmx"
"_build/install/default/lib/UnionFind/Partition2.ml"
"_build/install/default/lib/UnionFind/Partition3.cmi"
"_build/install/default/lib/UnionFind/Partition3.cmt"
"_build/install/default/lib/UnionFind/Partition3.cmx"
"_build/install/default/lib/UnionFind/Partition3.ml"
"_build/install/default/lib/UnionFind/UnionFind.a"
"_build/install/default/lib/UnionFind/UnionFind.cma"
"_build/install/default/lib/UnionFind/UnionFind.cmxa"
"_build/install/default/lib/UnionFind/UnionFind.cmxs"
"_build/install/default/lib/UnionFind/dune-package"
"_build/install/default/lib/UnionFind/opam"
"_build/install/default/lib/UnionFind/unionFind.cmi"
"_build/install/default/lib/UnionFind/unionFind.cmt"
"_build/install/default/lib/UnionFind/unionFind.cmx"
"_build/install/default/lib/UnionFind/unionFind.ml"
]
doc: [
"_build/install/default/doc/UnionFind/LICENSE"
"_build/install/default/doc/UnionFind/README.md"
]