, o : oracle('a, 'b), ttl : Chain.ttl) : unit Extends TTL of an oracle. * singature is a named argument and thus optional. Must be the same as for Oracle.register * o is the oracle being extended * ttl must be RelativeTTL . The time to live of o will be extended by this value. query_fee Oracle.query_fee(o : oracle('a, 'b)) : int Returns the query fee of the oracle query Oracle.query(o : oracle('a, 'b), q : 'a, qfee : int, qttl : Chain.ttl, rttl : Chain.ttl) : oracle_query('a, 'b) Asks the oracle a question. * The qfee is the query fee debited to the contract account ( Contract.address ). * The qttl controls the last height at which the oracle can submit a response and can be either fixed or relative. * The rttl must be relative and controls how long an answer is kept on the chain. The call fails if the oracle could expire before an answer. get_answer Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b) Checks what is the optional query answer expiry Oracle.expiry(o : oracle('a, 'b)) : int Ask the oracle when it expires. The result is the block height at which it will happen. check Oracle.check(o : oracle('a, 'b)) : bool Returns true iff the oracle o exists and has correct type check_query Oracle.check_query(o : oracle('a, 'b), q : oracle_query('a, 'b)) : bool It returns true iff the oracle query exist and has the expected type. Includable namespaces These need to be explicitly included (with .aes suffix) Bitwise Bitwise operations on arbitrary precision integers. bsr Bitwise.bsr(n : int, x : int) : int Logical bit shift x right n positions. bsl Bitwise.bsl(n : int, x : int) : int Logical bit shift x left n positions. bsli Bitwise.bsli(n : int, x : int, lim : int) : int Logical bit shift x left n positions, limit to lim bits. band Bitwise.band(x : int, y : int) : int Bitwise and of x and y . bor Bitwise.bor(x : int, y : int) : int Bitwise or of x and y . bxor Bitwise.bxor(x : int, y : int) : int Bitwise xor of x and y . bnot Bitwise.bnot(x : int) : int Bitwise not of x . Defined and implemented as bnot(x) = bxor(x, -1) . uband Bitwise.uband(x : int, y : int) : int Bitwise and of non-negative numbers x and y . ubor Bitwise.ubor(x : int, y : int) : int Bitwise or of non-negative x and y . ubxor Bitwise.ubxor(x : int, y : int) : int Bitwise xor of non-negative x and y . BLS12_381 Types fr Built-in (Montgomery) integer representation 32 bytes fp Built-in (Montgomery) integer representation 48 bytes fp2 record fp2 = { x1 : fp, x2 : fp }` g1 record g1 = { x : fp, y : fp, z : fp } g2 record g2 = { x : fp2, y : fp2, z : fp2 } gt record gt = { x1 : fp, x2 : fp, x3 : fp, x4 : fp, x5 : fp, x6 : fp, x7 : fp, x8 : fp, x9 : fp, x10 : fp, x11 : fp, x12 : fp } Functions pairing_check BLS12_381.pairing_check(xs : list(g1), ys : list(g2)) : bool Pairing check of a list of points, xs and ys should be of equal length. int_to_fr BLS12_381.int_to_fr(x : int) : fr Convert an integer to an fr - a 32 bytes internal (Montgomery) integer representation. int_to_fp BLS12_381.int_to_fp(x : int) : fp Convert an integer to an fp - a 48 bytes internal (Montgomery) integer representation. fr_to_int BLS12_381.fr_to_int(x : fr) : int Convert a fr value into an integer. fp_to_int BLS12_381.fp_to_int(x : fp) : int Convert a fp value into an integer. mk_g1 BLS12_381.mk_g1(x : int, y : int, z : int) : g1 Construct a g1 point from three integers. mk_g2 BLS12_381.mk_g2(x1 : int, x2 : int, y1 : int, y2 : int, z1 : int, z2 : int) : g2 Construct a g2 point from six integers. g1_neg BLS12_381.g1_neg(p : g1) : g1 Negate a g1 value. g1_norm BLS12_381.g1_norm(p : g1) : g1 Normalize a g1 value. g1_valid BLS12_381.g1_valid(p : g1) : bool Check that a g1 value is a group member. g1_is_zero BLS12_381.g1_is_zero(p : g1) : bool Check if a g1 value corresponds to the zero value of the group. g1_add BLS12_381.g1_add(p : g1, q : g1) : g1 Add two g1 values. g1_mul BLS12_381.g1_mul(k : fr, p : g1) : g1 Scalar multiplication for g1 . g2_neg BLS12_381.g2_neg(p : g2) : g2 Negate a g2 value. g2_norm BLS12_381.g2_norm(p : g2) : g2 Normalize a g2 value. g2_valid BLS12_381.g2_valid(p : g2) : bool Check that a g2 value is a group member. g2_is_zero BLS12_381.g2_is_zero(p : g2) : bool Check if a g2 value corresponds to the zero value of the group. g2_add BLS12_381.g2_add(p : g2, q : g2) : g2 Add two g2 values. g2_mul BLS12_381.g2_mul(k : fr, p : g2) : g2 Scalar multiplication for g2 . gt_inv BLS12_381.gt_inv(p : gt) : gt Invert a gt value. gt_add BLS12_381.gt_add(p : gt, q : gt) : gt Add two gt values. gt_mul BLS12_381.gt_mul(p : gt, q : gt) : gt Multiply two gt values. gt_pow BLS12_381.gt_pow(p : gt, k : fr) : gt Calculate exponentiation p ^ k . gt_is_one BLS12_381.gt_is_one(p : gt) : bool Compare a gt value to the unit value of the Gt group. pairing BLS12_381.pairing(p : g1, q : g2) : gt Compute the pairing of a g1 value and a g2 value. miller_loop BLS12_381.miller_loop(p : g1, q : g2) : gt Do the Miller loop stage of pairing for g1 and g2 . final_exp BLS12_381.final_exp(p : gt) : gt Perform the final exponentiation step of pairing for a gt value. Func Functional combinators. id Func.id(x : 'a) : 'a Identity function. Returns its argument. const Func.const(x : 'a) : 'b => 'a = (y) => x Constant function constructor. Given x returns a function that returns x regardless of its argument. flip Func.flip(f : ('a, 'b) => 'c) : ('b, 'a) => 'c Switches order of arguments of arity 2 function. comp Func.comp(f : 'b => 'c, g : 'a => 'b) : 'a => 'c Function composition. comp(f, g)(x) == f(g(x)) . pipe Func.pipe(f : 'a => 'b, g : 'b => 'c) : 'a => 'c Flipped function composition. pipe(f, g)(x) == g(f(x)) . rapply Func.rapply(x : 'a, f : 'a => 'b) : 'b Reverse application. rapply(x, f) == f(x) . recur Func.recur(f : ('arg => 'res, 'arg) => 'res) : 'arg => 'res The Z combinator. Allows performing local recursion and having anonymous recursive lambdas. To make function A => B recursive the user needs to transform it to take two arguments instead \u2013 one of type A => B which is going to work as a self-reference, and the other one of type A which is the original argument. Therefore, transformed function should have (A => B, A) => B signature. Example usage: let factorial = recur((fac, n) => if(n < 2) 1 else n * fac(n - 1)) If the function is going to take more than one argument it will need to be either tuplified or have curried out latter arguments. Example (factorial with custom step): // tuplified version let factorial_t(n, step) = let fac(rec, args) = let (n, step) = args if(n < 2) 1 else n * rec((n - step, step)) recur(fac)((n, step)) // curried version let factorial_c(n, step) = let fac(rec, n) = (step) => if(n < 2) 1 else n * rec(n - 1)(step) recur(fac)(n)(step) iter Func.iter(n : int, f : 'a => 'a) : 'a => 'a n th composition of f with itself, for instance iter(3, f) is equivalent to (x) => f(f(f(x))) . curry Func.curry2(f : ('a, 'b) => 'c) : 'a => ('b => 'c) Func.curry3(f : ('a, 'b, 'c) => 'd) : 'a => ('b => ('c => 'd)) Turns a function that takes n arguments into a curried function that takes one argument and returns a function that waits for the rest in the same manner. For instance curry2((a, b) => a + b)(1)(2) == 3 . uncurry Func.uncurry2(f : 'a => ('b => 'c)) : ('a, 'b) => 'c Func.uncurry3(f : 'a => ('b => ('c => 'd))) : ('a, 'b, 'c) => 'd Opposite to curry . tuplify Func.tuplify2(f : ('a, 'b) => 'c) : (('a * 'b)) => 'c Func.tuplify3(f : ('a, 'b, 'c) => 'd) : 'a * 'b * 'c => 'd Turns a function that takes n arguments into a function that takes an n-tuple. untuplify Func.untuplify2(f : 'a * 'b => 'c) : ('a, 'b) => 'c Func.untuplify3(f : 'a * 'b * 'c => 'd) : ('a, 'b, 'c) => 'd Opposite to tuplify . Frac This namespace provides operations on rational numbers. A rational number is represented as a fraction of two integers which are stored internally in the frac datatype. The datatype consists of three constructors Neg/2 , Zero/0 and Pos/2 which determine the sign of the number. Both values stored in Neg and Pos need to be strictly positive integers. However, when creating a frac you should never use the constructors explicitly. Instead of that, always use provided functions like make_frac or from_int . This helps keeping the internal representation well defined. The described below functions take care of the normalization of the fractions \u2013 they won't grow if it is unnecessary. Please note that the size of frac can be still very big while the value is actually very close to a natural number \u2013 the division of two extremely big prime numbers will be as big as both of them. To face this issue the optimize function is provided. It will approximate the value of the fraction to fit in the given error margin and to shrink its size as much as possible. Important note: frac must not be compared using standard < -like operators. The operator comparison is not possible to overload at this moment, nor the language provides checkers to prevent unintended usage of them. Therefore the typechecker will allow that and the results of such comparison will be unspecified. You should use lt , geq , eq etc instead. Types frac datatype frac = Pos(int, int) | Zero | Neg(int, int) Internal representation of fractional numbers. First integer encodes the numerator and the second the denominator \u2013 both must be always positive, as the sign is being handled by the choice of the constructor. Functions make_frac Frac.make_frac(n : int, d : int) : frac Creates a fraction out of numerator and denominator. Automatically normalizes, so make_frac(2, 4) and make_frac(1, 2) will yield same results. num Frac.num(f : frac) : int Returns the numerator of a fraction. den Frac.den(f : frac) : int Returns the denominator of a fraction. to_pair Frac.to_pair(f : frac) : int * int Turns a fraction into a pair of numerator and denominator. sign Frac.sign(f : frac) : int Returns the signum of a fraction, -1, 0, 1 if negative, zero, positive respectively. to_str Frac.to_str(f : frac) : string Conversion to string. Does not display division by 1 or denominator if equals zero. simplify Frac.simplify(f : frac) : frac Reduces fraction to normal form if for some reason it is not in it. eq Frac.eq(a : frac, b : frac) : bool Checks if a is equal to b . neq Frac.neq(a : frac, b : frac) : bool Checks if a is not equal to b . geq Frac.geq(a : frac, b : frac) : bool Checks if a is greater or equal to b . leq Frac.leq(a : frac, b : frac) : bool Checks if a is lesser or equal to b . gt Frac.gt(a : frac, b : frac) : bool Checks if a is greater than b . lt Frac.lt(a : frac, b : frac) : bool Checks if a is lesser than b . min Frac.min(a : frac, b : frac) : frac Chooses lesser of the two fractions. max Frac.max(a : frac, b : frac) : frac Chooses greater of the two fractions. abs Frac.abs(f : frac) : frac Absolute value. from_int Frac.from_int(n : int) : frac From integer conversion. Effectively make_frac(n, 1) . floor Frac.floor(f : frac) : int Rounds a fraction to the nearest lesser or equal integer. ceil Frac.ceil(f : frac) : int Rounds a fraction to the nearest greater or equal integer. round_to_zero Frac.round_to_zero(f : frac) : int Rounds a fraction towards zero. Effectively ceil if lesser than zero and floor if greater. round_from_zero Frac.round_from_zero(f : frac) : int Rounds a fraction from zero. Effectively ceil if greater than zero and floor if lesser. round Frac.round(f : frac) : int Rounds a fraction to a nearest integer. If two integers are in the same distance it will choose the even one. add Frac.add(a : frac, b : frac) : frac Sum of the fractions. neg Frac.neg(a : frac) : frac Negation of the fraction. sub Frac.sub(a : frac, b : frac) : frac Subtraction of two fractions. inv Frac.inv(a : frac) : frac Inverts a fraction. Throws error if a is zero. mul Frac.mul(a : frac, b : frac) : frac Multiplication of two fractions. div Frac.div(a : frac, b : frac) : frac Division of two fractions. int_exp Frac.int_exp(b : frac, e : int) : frac Takes b to the power of e . The exponent can be a negative value. optimize Frac.optimize(f : frac, loss : frac) : frac Shrink the internal size of a fraction as much as possible by approximating it to the point where the error would exceed the loss value. is_sane Frac.is_sane(f : frac) : bool For debugging. If it ever returns false in a code that doesn't call frac constructors or accept arbitrary frac s from the surface you should report it as a bug If you expect getting calls with malformed frac s in your contract, you should use this function to verify the input. List This module contains common operations on lists like constructing, querying, traversing etc. is_empty List.is_empty(l : list('a)) : bool Returns true iff the list is equal to [] . first List.first(l : list('a)) : option('a) Returns Some of the first element of a list or None if the list is empty. tail List.tail(l : list('a)) : option(list('a)) Returns Some of a list without its first element or None if the list is empty. last List.last(l : list('a)) : option('a) Returns Some of the last element of a list or None if the list is empty. contains List.contains(e : 'a, l : list('a)) : bool Checks if list l contains element e . Equivalent to List.find(x => x == e, l) != None . find List.find(p : 'a => bool, l : list('a)) : option('a) Finds first element of l fulfilling predicate p as Some or None if no such element exists. find_indices List.find_indices(p : 'a => bool, l : list('a)) : list(int) Returns list of all indices of elements from l that fulfill the predicate p . nth List.nth(n : int, l : list('a)) : option('a) Gets n th element of l as Some or None if l is shorter than n + 1 or n is negative. get List.get(n : int, l : list('a)) : 'a Gets n th element of l forcefully, throwing and error if l is shorter than n + 1 or n is negative. length List.length(l : list('a)) : int Returns length of a list. from_to List.from_to(a : int, b : int) : list(int) Creates an ascending sequence of all integer numbers between a and b (including a and b ). from_to_step List.from_to_step(a : int, b : int, step : int) : list(int) Creates an ascending sequence of integer numbers betweeen a and b jumping by given step . Includes a and takes b only if (b - a) mod step == 0 . step should be bigger than 0. replace_at List.replace_at(n : int, e : 'a, l : list('a)) : list('a) Replaces n th element of l with e . Throws an error if n is negative or would cause an overflow. insert_at List.insert_at(n : int, e : 'a, l : list('a)) : list('a) Inserts e into l to be on position n by shifting following elements further. For instance, insert_at(2, 9, [1,2,3,4]) will yield [1,2,9,3,4] . insert_by List.insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) Assuming that cmp represents < comparison, inserts x before the first element in the list l which is greater than it. For instance, insert_by((a, b) => a < b, 4, [1,2,3,5,6,7]) will yield [1,2,3,4,5,6,7] foldr List.foldr(cons : ('a, 'b) => 'b, nil : 'b, l : list('a)) : 'b Right fold of a list. Assuming l = [x, y, z] will return f(x, f(y, f(z, nil))) . Not tail recursive. foldl List.foldl(rcons : ('b, 'a) => 'b, acc : 'b, l : list('a)) : 'b Left fold of a list. Assuming l = [x, y, z] will return f(f(f(acc, x), y), z) . Tail recursive. foreach List.foreach(l : list('a), f : 'a => unit) : unit Evaluates f on each element of a list. reverse List.reverse(l : list('a)) : list('a) Returns a copy of l with reversed order of elements. map List.map(f : 'a => 'b, l : list('a)) : list('b) Maps function f over a list. For instance map((x) => x == 0, [1, 2, 0, 3, 0]) will yield [false, false, true, false, true] flat_map List.flat_map(f : 'a => list('b), l : list('a)) : list('b) Maps f over a list and then flattens it. For instance flat_map((x) => [x, x * 10], [1, 2, 3]) will yield [1, 10, 2, 20, 3, 30] filter List.filter(p : 'a => bool, l : list('a)) : list('a) Filters out elements of l that fulfill predicate p . For instance filter((x) => x > 0, [-1, 1, -2, 0, 1, 2, -3]) will yield [1, 1, 2] take List.take(n : int, l : list('a)) : list('a) Takes n first elements of l . Fails if n is negative. If n is greater than length of a list it will return whole list. drop List.drop(n : int, l : list('a)) : list('a) Removes n first elements of l . Fails if n is negative. If n is greater than length of a list it will return [] . take_while List.take_while(p : 'a => bool, l : list('a)) : list('a) Returns longest prefix of l in which all elements fulfill p . drop_while List.drop_while(p : 'a => bool, l : list('a)) : list('a) Removes longest prefix from l in which all elements fulfill p . partition List.partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) Separates elements of l that fulfill p and these that do not. Elements fulfilling predicate will be in the right list. For instance partition((x) => x > 0, [-1, 1, -2, 0, 1, 2, -3]) will yield ([1, 1, 2], [-1, -2, 0, -3]) flatten List.flatten(ll : list(list('a))) : list('a) Flattens a list of lists into a one list. all List.all(p : 'a => bool, l : list('a)) : bool Checks if all elements of a list fulfill predicate p . any List.any(p : 'a => bool, l : list('a)) : bool Checks if any element of a list fulfills predicate p . sum List.sum(l : list(int)) : int Sums elements of a list. Returns 0 if the list is empty. product List.product(l : list(int)) : int Multiplies elements of a list. Returns 1 if the list is empty. zip_with List.zip_with(f : ('a, 'b) => 'c, l1 : list('a), l2 : list('b)) : list('c) \"zips\" two lists with a function. n-th element of resulting list will be equal to f(x1, x2) where x1 and x2 are n-th elements of l1 and l2 respectively. Will cut off the tail of the longer list. For instance zip_with((a, b) => a + b, [1,2], [1,2,3]) will yield [2,4] zip List.zip(l1 : list('a), l2 : list('b)) : list('a * 'b) Special case of zip_with where the zipping function is (a, b) => (a, b) . unzip List.unzip(l : list('a * 'b)) : list('a) * list('b) Opposite to the zip operation. Takes a list of pairs and returns pair of lists with respective elements on same indices. merge List.merge(lesser_cmp : ('a, 'a) => bool, l1 : list('a), l2 : list('a)) : list('a) Merges two sorted lists into a single sorted list. O(length(l1) + length(l2)) sort List.sort(lesser_cmp : ('a, 'a) => bool, l : list('a)) : list('a) Sorts a list using given comparator. lesser_cmp(x, y) should return true iff x < y . If lesser_cmp is not transitive or there exists an element x such that lesser_cmp(x, x) or there exists a pair of elements x and y such that lesser_cmp(x, y) && lesser_cmp(y, x) then the result is undefined. O(length(l) * log_2(length(l))). intersperse List.intersperse(delim : 'a, l : list('a)) : list('a) Intersperses elements of l with delim . Does nothing on empty lists and singletons. For instance intersperse(0, [1, 2, 3, 4]) will yield [1, 0, 2, 0, 3, 0, 4] enumerate List.enumerate(l : list('a)) : list(int * 'a) Equivalent to zip with [0..length(l)] , but slightly faster. Option Common operations on option types and lists of option s. is_none Option.is_none(o : option('a)) : bool Returns true iff o == None is_some Option.is_some(o : option('a)) : bool Returns true iff o is not None . match Option.match(n : 'b, s : 'a => 'b, o : option('a)) : 'b Behaves like pattern matching on option using two case functions. default Option.default(def : 'a, o : option('a)) : 'a Escapes option wrapping by providing default value for None . force Option.force(o : option('a)) : 'a Forcefully escapes the option wrapping assuming it is Some . Aborts on None . force_msg Option.force_msg(o : option('a), err : string) : 'a Forcefully escapes the option wrapping assuming it is Some . Aborts with err error message on None . contains Option.contains(e : 'a, o : option('a)) : bool Returns true if and only if o contains element equal to e . Equivalent to Option.match(false, x => x == e, o) . on_elem Option.on_elem(o : option('a), f : 'a => unit) : unit Evaluates f on element under Some . Does nothing on None . map Option.map(f : 'a => 'b, o : option('a)) : option('b) Maps element under Some . Leaves None unchanged. map2 Option.map2(f : ('a, 'b) => 'c, o1 : option('a), o2 : option('b)) : option('c) Applies arity 2 function over two option s' elements. Returns Some iff both of o1 and o2 were Some , or None otherwise. For instance map2((a, b) => a + b, Some(1), Some(2)) will yield Some(3) and map2((a, b) => a + b, Some(1), None) will yield None . map3 Option.map3(f : ('a, 'b, 'c) => 'd, o1 : option('a), o2 : option('b), o3 : option('c)) : option('d) Same as map2 but with arity 3 function. app_over Option.app_over(f : option ('a => 'b), o : option('a)) : option('b) Applies function under option over argument under option . If either of them is None the result will be None as well. For instance app_over(Some((x) => x + 1), Some(1)) will yield Some(2) and app_over(Some((x) => x + 1), None) will yield None . flat_map Option.flat_map(f : 'a => option('b), o : option('a)) : option('b) Performs monadic bind on an option . Extracts element from o (if present) and forms new option from it. For instance flat_map((x) => Some(x + 1), Some(1)) will yield Some(2) and flat_map((x) => Some(x + 1), None) will yield None . to_list Option.to_list(o : option('a)) : list('a) Turns o into an empty (if None ) or singleton (if Some ) list. filter_options Option.filter_options(l : list(option('a))) : list('a) Removes None s from list and unpacks all remaining Some s. For instance filter_options([Some(1), None, Some(2)]) will yield [1, 2] . seq_options Option.seq_options(l : list (option('a))) : option (list('a)) Tries to unpack all elements of a list from Some s. Returns None if at least element of l is None . For instance seq_options([Some(1), Some(2)]) will yield Some([1, 2]) , but seq_options([Some(1), Some(2), None]) will yield None . choose Option.choose(o1 : option('a), o2 : option('a)) : option('a) Out of two option s choose the one that is Some , or None if both are None s. choose_first Option.choose_first(l : list(option('a))) : option('a) Same as choose , but chooses from a list insted of two arguments. Pair Common operations on 2-tuples. fst Pair.fst(t : ('a * 'b)) : 'a First element projection. snd Pair.snd(t : ('a * 'b)) : 'b Second element projection. map1 Pair.map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) Applies function over first element. map2 Pair.map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) Applies function over second element. bimap Pair.bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) Applies functions over respective elements. swap Pair.swap(t : ('a * 'b)) : ('b * 'a) Swaps elements. Set Types record set('a) = { to_map : map('a, unit) } Functions new Set.new() : set('a) Returns an empty set member member(e : 'a, s : set('a)) : bool Checks if the element e is present in the set s insert insert(e : 'a, s : set('a)) : set('a) Inserts the element e in the set s delete Set.delete(e : 'a, s : set('a)) : set('a) Removes the element e from the set s size size(s : set('a)) : int Returns the number of elements in the set s to_list Set.to_list(s : set('a)) : list('a) Returns a list containing the elements of the set s from_list Set.from_list(l : list('a)) : set('a) Turns the list l into a set filter Set.filter(p : 'a => bool, s : set('a)) : set('a) Filters out elements of s that fulfill predicate p fold Set.fold(f : ('a, 'b) => 'b, acc : 'b, s : set('a)) : 'b Folds the function f over every element in the set s and returns the final value of the accumulator acc . subtract Set.subtract(s1 : set('a), s2 : set('a)) : set('a) Returns the elements of s1 that are not members of s2 intersection Set.intersection(s1 : set('a), s2 : set('a)) : set('a) Returns the intersection of the two sets s1 and s2 intersection_list Set.intersection_list(sets : list(set('a))) : set('a) Returns the intersection of all the sets in the given list union Set.union(s1 : set('a), s2 : set('a)) : set('a) Returns the union of the two sets s1 and s2 union_list Set.union_list(sets : list(set('a))) : set('a) Returns the union of all the sets in the given list String Operations on the string type. A string is a UTF-8 encoded byte array. length length(s : string) : int The length of a string. Note: not equivalent to byte size of the string, rather List.length(String.to_list(s)) concat concat(s1 : string, s2 : string) : string Concatenates s1 and s2 . concats concats(ss : list(string)) : string Concatenates a list of strings. to_list to_list(s : string) : list(char) Converts a string to a list of char - the code points are normalized, but composite characters are possibly converted to multiple char s. For example the string \"\ud83d\ude1ci\u0307\" is converted to [128540,105,775] - where the smiley is the first code point and the strangely dotted i becomes [105, 775] . from_list from_list(cs : list(char)) : string Converts a list of characters into a normalized UTF-8 string. to_lower to_lower(s : string) : string Converts a string to lowercase. to_upper to_upper(s : string) : string Converts a string to uppercase. at at(ix : int, s : string) : option(char) Returns the character/codepoint at (zero-based) index ix . Basically the equivalent to List.nth(ix, String.to_list(s)) . split split(ix : int, s:string) : string * string Splits a string at (zero-based) index ix . contains contains(str : string, pat : string) : option(int) Searches for pat in str , returning Some(ix) if pat is a substring of str starting at position ix , otherwise returns None . tokens tokens(str : string, pat : string) : list(string) Splits str into tokens, pat is the divider of tokens. to_int to_int(s : string) : option(int) Converts a decimal (\"123\", \"-253\") or a hexadecimal (\"0xa2f\", \"-0xBBB\") string into an integer. If the string doesn't contain a valid number None is returned. sha3 sha3(s : string) : hash Computes the SHA3/Keccak hash of the string. sha256 sha256(s : string) : hash Computes the SHA256 hash of the string. blake2b blake2b(s : string) : hash Computes the Blake2B hash of the string. Triple fst Triple.fst(t : ('a * 'b * 'c)) : 'a First element projection. snd Triple.snd(t : ('a * 'b * 'c)) : 'b Second element projection. thd Triple.thd(t : ('a * 'b * 'c)) : 'c Third element projection. map1 Triple.map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) Applies function over first element. map2 Triple.map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) Applies function over second element. map3 Triple.map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) Applies function over third element. trimap Triple.trimap(f : 'a => 'x, g : 'b => 'y, h : 'c => 'z, t : ('a * 'b * 'c)) : ('x * 'y * 'z) Applies functions over respective elements. swap Triple.swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) Swaps first and third element. rotr Triple.rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) Cyclic rotation of the elements to the right. rotl Triple.rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) Cyclic rotation of the elements to the left.","title":"Standard library"},{"location":"sophia_stdlib/#standard-library","text":"Sophia language offers standard library that consists of several namespaces. Some of them are already in the scope and do not need any actions to be used, while the others require some files to be included. The out-of-the-box namespaces are: Address AENS Auth Bits Bytes Call Chain Char Contract Crypto Int Map Oracle The following ones need to be included as regular files with .aes suffix, for example include \"List.aes\" Bitwise BLS12_381 Func Frac List Option Pair Set String Triple","title":"Standard library"},{"location":"sophia_stdlib/#builtin-namespaces","text":"They are available without any explicit includes.","title":"Builtin namespaces"},{"location":"sophia_stdlib/#address","text":"","title":"Address"},{"location":"sophia_stdlib/#aens","text":"The following functionality is available for interacting with the \u00e6ternity naming system (AENS). If owner is equal to Contract.address the signature signature is ignored, and can be left out since it is a named argument. Otherwise we need a signature to prove that we are allowed to do AENS operations on behalf of owner . The signature is tied to a network id , i.e. the signature material should be prefixed by the network id.","title":"AENS"},{"location":"sophia_stdlib/#auth","text":"","title":"Auth"},{"location":"sophia_stdlib/#bits","text":"","title":"Bits"},{"location":"sophia_stdlib/#bytes","text":"","title":"Bytes"},{"location":"sophia_stdlib/#call","text":"Values related to the call to the current contract","title":"Call"},{"location":"sophia_stdlib/#chain","text":"Values and functions related to the chain itself and other entities that live on it.","title":"Chain"},{"location":"sophia_stdlib/#char","text":"","title":"Char"},{"location":"sophia_stdlib/#contract","text":"Values related to the current contract","title":"Contract"},{"location":"sophia_stdlib/#crypto","text":"","title":"Crypto"},{"location":"sophia_stdlib/#int","text":"","title":"Int"},{"location":"sophia_stdlib/#map","text":"","title":"Map"},{"location":"sophia_stdlib/#oracle","text":"","title":"Oracle"},{"location":"sophia_stdlib/#includable-namespaces","text":"These need to be explicitly included (with .aes suffix)","title":"Includable namespaces"},{"location":"sophia_stdlib/#bitwise","text":"Bitwise operations on arbitrary precision integers.","title":"Bitwise"},{"location":"sophia_stdlib/#bls12_381","text":"","title":"BLS12\u000295\u0003381"},{"location":"sophia_stdlib/#func","text":"Functional combinators.","title":"Func"},{"location":"sophia_stdlib/#frac","text":"This namespace provides operations on rational numbers. A rational number is represented as a fraction of two integers which are stored internally in the frac datatype. The datatype consists of three constructors Neg/2 , Zero/0 and Pos/2 which determine the sign of the number. Both values stored in Neg and Pos need to be strictly positive integers. However, when creating a frac you should never use the constructors explicitly. Instead of that, always use provided functions like make_frac or from_int . This helps keeping the internal representation well defined. The described below functions take care of the normalization of the fractions \u2013 they won't grow if it is unnecessary. Please note that the size of frac can be still very big while the value is actually very close to a natural number \u2013 the division of two extremely big prime numbers will be as big as both of them. To face this issue the optimize function is provided. It will approximate the value of the fraction to fit in the given error margin and to shrink its size as much as possible. Important note: frac must not be compared using standard < -like operators. The operator comparison is not possible to overload at this moment, nor the language provides checkers to prevent unintended usage of them. Therefore the typechecker will allow that and the results of such comparison will be unspecified. You should use lt , geq , eq etc instead.","title":"Frac"},{"location":"sophia_stdlib/#list","text":"This module contains common operations on lists like constructing, querying, traversing etc.","title":"List"},{"location":"sophia_stdlib/#option","text":"Common operations on option types and lists of option s.","title":"Option"},{"location":"sophia_stdlib/#pair","text":"Common operations on 2-tuples.","title":"Pair"},{"location":"sophia_stdlib/#set_1","text":"","title":"Set"},{"location":"sophia_stdlib/#string","text":"Operations on the string type. A string is a UTF-8 encoded byte array.","title":"String"},{"location":"sophia_stdlib/#triple","text":"","title":"Triple"},{"location":"sophia_syntax/","text":"Syntax Lexical syntax Comments Single line comments start with // and block comments are enclosed in /* and */ and can be nested. Keywords contract include let switch type record datatype if elif else function stateful payable true false mod public entrypoint private indexed namespace interface main using as for hiding Tokens Id = [a-z_][A-Za-z0-9_']* identifiers start with a lower case letter. Con = [A-Z][A-Za-z0-9_']* constructors start with an upper case letter. QId = (Con\\.)+Id qualified identifiers (e.g. Map.member ) QCon = (Con\\.)+Con qualified constructor TVar = 'Id type variable (e.g 'a , 'b ) Int = [0-9]+(_[0-9]+)*|0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)* integer literal with optional _ separators Bytes = #[0-9A-Fa-f]+(_[0-9A-Fa-f]+)* byte array literal with optional _ separators String string literal enclosed in \" with escape character \\ Char character literal enclosed in ' with escape character \\ AccountAddress base58-encoded 32 byte account pubkey with ak_ prefix ContractAddress base58-encoded 32 byte contract address with ct_ prefix OracleAddress base58-encoded 32 byte oracle address with ok_ prefix OracleQueryId base58-encoded 32 byte oracle query id with oq_ prefix Valid string escape codes are Escape ASCII \\b 8 \\t 9 \\n 10 \\v 11 \\f 12 \\r 13 \\e 27 \\xHexDigits HexDigits See the identifier encoding scheme for the details on the base58 literals. Layout blocks Sophia uses Python-style layout rules to group declarations and statements. A layout block with more than one element must start on a separate line and be indented more than the currently enclosing layout block. Blocks with a single element can be written on the same line as the previous token. Each element of the block must share the same indentation and no part of an element may be indented less than the indentation of the block. For instance contract Layout = function foo () = 0 // no layout function bar () = // layout block starts on next line let x = foo () // indented more than 2 spaces x + 1 // the '+' is indented more than the 'x' Notation In describing the syntax below, we use the following conventions: Upper-case identifiers denote non-terminals (like Expr ) or terminals with some associated value (like Id ). Keywords and symbols are enclosed in single quotes: 'let' or '=' . Choices are separated by vertical bars: | . Optional elements are enclosed in [ square brackets ] . ( Parentheses ) are used for grouping. Zero or more repetitions are denoted by a postfix * , and one or more repetitions by a + . Block(X) denotes a layout block of X s. Sep(X, S) is short for [X (S X)*] , i.e. a possibly empty sequence of X s separated by S s. Sep1(X, S) is short for X (S X)* , i.e. same as Sep , but must not be empty. Declarations A Sophia file consists of a sequence of declarations in a layout block. File ::= Block ( TopDecl ) TopDecl ::= [ ' payable ' ] [ ' main ' ] ' contract ' Con [ Implement ] '=' Block ( Decl ) | ' contract ' ' interface ' Con [ Implement ] '=' Block ( Decl ) | ' namespace ' Con '=' Block ( Decl ) | '@ compiler ' PragmaOp Version | ' include ' String | Using Implement ::= ':' Sep1 ( Con , ',' ) Decl ::= ' type ' Id [ '(' TVar * ')' ] '=' TypeAlias | ' record ' Id [ '(' TVar * ')' ] '=' RecordType | ' datatype ' Id [ '(' TVar * ')' ] '=' DataType | ( EModifier * ' entrypoint ' | FModifier * ' function ' ) Block ( FunDecl ) | Using FunDecl ::= Id ':' Type // Type signature | Id Args [ ':' Type ] '=' Block ( Stmt ) // Definition | Id Args [ ':' Type ] Block ( GuardedDef ) // Guarded definitions GuardedDef ::= '|' Sep1 ( Expr , ',' ) '=' Block ( Stmt ) Using ::= ' using ' Con [ ' as ' Con ] [ UsingParts ] UsingParts ::= ' for ' ' [ ' Sep1 ( Id , ',' ) ']' | ' hiding ' ' [ ' Sep1 ( Id , ',' ) ']' PragmaOp ::= '<' | ' =< ' | ' == ' | ' >= ' | '>' Version ::= Sep1 ( Int , '.' ) EModifier ::= ' payable ' | ' stateful ' FModifier ::= ' stateful ' | ' private ' Args ::= '(' Sep ( Pattern , ',' ) ')' Contract declarations must appear at the top-level. For example, contract Test = type t = int entrypoint add ( x : t , y : t ) = x + y There are three forms of type declarations: type aliases (declared with the type keyword), record type definitions ( record ) and data type definitions ( datatype ): TypeAlias ::= Type RecordType ::= '{' Sep ( FieldType , ',' ) '}' DataType ::= Sep1 ( ConDecl , '|' ) FieldType ::= Id ':' Type ConDecl ::= Con [ '(' Sep1 ( Type , ',' ) ')' ] For example, record point ( 'a ) = { x : 'a , y : 'a } datatype shape ( 'a ) = Circle ( point ( 'a ), 'a ) | Rect ( point ( 'a ), point ( 'a )) type int_shape = shape ( int ) Types Type ::= Domain ' => ' Type // Function type | Type '(' Sep ( Type , ',' ) ')' // Type application | '(' Type ')' // Parens | ' unit ' | Sep ( Type , '*' ) // Tuples | Id | QId | TVar Domain ::= Type // Single argument | '(' Sep ( Type , ',' ) ')' // Multiple arguments The function type arrow associates to the right. Example, 'a => list ( 'a ) => ( int * list ( 'a )) Statements Function bodies are blocks of statements , where a statement is one of the following Stmt ::= ' switch ' ' ( ' Expr ')' Block ( Case ) | ' if ' ' ( ' Expr ')' Block ( Stmt ) | ' elif ' ' ( ' Expr ')' Block ( Stmt ) | ' else ' Block ( Stmt ) | ' let ' LetDef | Using | Expr LetDef ::= Id Args [ ':' Type ] '=' Block ( Stmt ) // Function definition | Pattern '=' Block ( Stmt ) // Value definition Case ::= Pattern ' => ' Block ( Stmt ) | Pattern Block ( GuardedCase ) GuardedCase ::= '|' Sep1 ( Expr , ',' ) ' => ' Block ( Stmt ) Pattern ::= Expr if statements can be followed by zero or more elif statements and an optional final else statement. For example, let x : int = 4 switch ( f ( x )) None => 0 Some ( y ) => if ( y > 10 ) \"too big\" elif ( y < 3 ) \"too small\" else \"just right\" Expressions Expr ::= '(' LamArgs ')' ' => ' Block ( Stmt ) // Anonymous function (x) => x + 1 | '(' BinOp ')' // Operator lambda (+) | ' if ' ' ( ' Expr ')' Expr ' else ' Expr // If expression if(x < y) y else x | Expr ':' Type // Type annotation 5 : int | Expr BinOp Expr // Binary operator x + y | UnOp Expr // Unary operator ! b | Expr '(' Sep ( Expr , ',' ) ')' // Application f(x, y) | Expr '.' Id // Projection state.x | Expr '[' Expr ']' // Map lookup map[key] | Expr '{' Sep ( FieldUpdate , ',' ) '}' // Record or map update r{ fld[key].x = y } | '[' Sep ( Expr , ',' ) ']' // List [1, 2, 3] | '[' Expr '|' Sep ( Generator , ',' ) ']' // List comprehension [k | x <- [1], if (f(x)), let k = x+1] | '[' Expr ' .. ' Expr ']' // List range [1..n] | '{' Sep ( FieldUpdate , ',' ) '}' // Record or map value {x = 0, y = 1}, {[key] = val} | '(' Expr ')' // Parens (1 + 2) * 3 | '(' Expr '=' Expr ')' // Assign pattern (y = x::_) | Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token | Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, \"foo\", '%' | AccountAddress | ContractAddress // Chain identifiers | OracleAddress | OracleQueryId // Chain identifiers Generator ::= Pattern ' <- ' Expr // Generator | ' if ' ' ( ' Expr ')' // Guard | LetDef // Definition LamArgs ::= '(' Sep ( LamArg , ',' ) ')' LamArg ::= Id [ ':' Type ] FieldUpdate ::= Path '=' Expr Path ::= Id // Record field | '[' Expr ']' // Map key | Path '.' Id // Nested record field | Path '[' Expr ']' // Nested map key BinOp ::= ' || ' | ' && ' | '<' | '>' | ' =< ' | ' >= ' | ' == ' | ' != ' | ' :: ' | ' ++ ' | '+' | '-' | '*' | '/' | ' mod ' | '^' | ' |> ' UnOp ::= '-' | '!' Operators types Operators Type - + * / mod ^ arithmetic operators ! && || logical operators == != < > =< >= comparison operators :: ++ list operators |> functional operators Operator precedence In order of highest to lowest precedence. Operators Associativity ! right ^ left * / mod left - (unary) right + - left :: ++ right < > =< >= == != none && right || right |> left","title":"Syntax"},{"location":"sophia_syntax/#syntax","text":"","title":"Syntax"},{"location":"sophia_syntax/#lexical-syntax","text":"","title":"Lexical syntax"},{"location":"sophia_syntax/#comments","text":"Single line comments start with // and block comments are enclosed in /* and */ and can be nested.","title":"Comments"},{"location":"sophia_syntax/#keywords","text":"contract include let switch type record datatype if elif else function stateful payable true false mod public entrypoint private indexed namespace interface main using as for hiding","title":"Keywords"},{"location":"sophia_syntax/#tokens","text":"Id = [a-z_][A-Za-z0-9_']* identifiers start with a lower case letter. Con = [A-Z][A-Za-z0-9_']* constructors start with an upper case letter. QId = (Con\\.)+Id qualified identifiers (e.g. Map.member ) QCon = (Con\\.)+Con qualified constructor TVar = 'Id type variable (e.g 'a , 'b ) Int = [0-9]+(_[0-9]+)*|0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)* integer literal with optional _ separators Bytes = #[0-9A-Fa-f]+(_[0-9A-Fa-f]+)* byte array literal with optional _ separators String string literal enclosed in \" with escape character \\ Char character literal enclosed in ' with escape character \\ AccountAddress base58-encoded 32 byte account pubkey with ak_ prefix ContractAddress base58-encoded 32 byte contract address with ct_ prefix OracleAddress base58-encoded 32 byte oracle address with ok_ prefix OracleQueryId base58-encoded 32 byte oracle query id with oq_ prefix Valid string escape codes are Escape ASCII \\b 8 \\t 9 \\n 10 \\v 11 \\f 12 \\r 13 \\e 27 \\xHexDigits HexDigits See the identifier encoding scheme for the details on the base58 literals.","title":"Tokens"},{"location":"sophia_syntax/#layout-blocks","text":"Sophia uses Python-style layout rules to group declarations and statements. A layout block with more than one element must start on a separate line and be indented more than the currently enclosing layout block. Blocks with a single element can be written on the same line as the previous token. Each element of the block must share the same indentation and no part of an element may be indented less than the indentation of the block. For instance contract Layout = function foo () = 0 // no layout function bar () = // layout block starts on next line let x = foo () // indented more than 2 spaces x + 1 // the '+' is indented more than the 'x'","title":"Layout blocks"},{"location":"sophia_syntax/#notation","text":"In describing the syntax below, we use the following conventions: Upper-case identifiers denote non-terminals (like Expr ) or terminals with some associated value (like Id ). Keywords and symbols are enclosed in single quotes: 'let' or '=' . Choices are separated by vertical bars: | . Optional elements are enclosed in [ square brackets ] . ( Parentheses ) are used for grouping. Zero or more repetitions are denoted by a postfix * , and one or more repetitions by a + . Block(X) denotes a layout block of X s. Sep(X, S) is short for [X (S X)*] , i.e. a possibly empty sequence of X s separated by S s. Sep1(X, S) is short for X (S X)* , i.e. same as Sep , but must not be empty.","title":"Notation"},{"location":"sophia_syntax/#declarations","text":"A Sophia file consists of a sequence of declarations in a layout block. File ::= Block ( TopDecl ) TopDecl ::= [ ' payable ' ] [ ' main ' ] ' contract ' Con [ Implement ] '=' Block ( Decl ) | ' contract ' ' interface ' Con [ Implement ] '=' Block ( Decl ) | ' namespace ' Con '=' Block ( Decl ) | '@ compiler ' PragmaOp Version | ' include ' String | Using Implement ::= ':' Sep1 ( Con , ',' ) Decl ::= ' type ' Id [ '(' TVar * ')' ] '=' TypeAlias | ' record ' Id [ '(' TVar * ')' ] '=' RecordType | ' datatype ' Id [ '(' TVar * ')' ] '=' DataType | ( EModifier * ' entrypoint ' | FModifier * ' function ' ) Block ( FunDecl ) | Using FunDecl ::= Id ':' Type // Type signature | Id Args [ ':' Type ] '=' Block ( Stmt ) // Definition | Id Args [ ':' Type ] Block ( GuardedDef ) // Guarded definitions GuardedDef ::= '|' Sep1 ( Expr , ',' ) '=' Block ( Stmt ) Using ::= ' using ' Con [ ' as ' Con ] [ UsingParts ] UsingParts ::= ' for ' ' [ ' Sep1 ( Id , ',' ) ']' | ' hiding ' ' [ ' Sep1 ( Id , ',' ) ']' PragmaOp ::= '<' | ' =< ' | ' == ' | ' >= ' | '>' Version ::= Sep1 ( Int , '.' ) EModifier ::= ' payable ' | ' stateful ' FModifier ::= ' stateful ' | ' private ' Args ::= '(' Sep ( Pattern , ',' ) ')' Contract declarations must appear at the top-level. For example, contract Test = type t = int entrypoint add ( x : t , y : t ) = x + y There are three forms of type declarations: type aliases (declared with the type keyword), record type definitions ( record ) and data type definitions ( datatype ): TypeAlias ::= Type RecordType ::= '{' Sep ( FieldType , ',' ) '}' DataType ::= Sep1 ( ConDecl , '|' ) FieldType ::= Id ':' Type ConDecl ::= Con [ '(' Sep1 ( Type , ',' ) ')' ] For example, record point ( 'a ) = { x : 'a , y : 'a } datatype shape ( 'a ) = Circle ( point ( 'a ), 'a ) | Rect ( point ( 'a ), point ( 'a )) type int_shape = shape ( int )","title":"Declarations"},{"location":"sophia_syntax/#types","text":"Type ::= Domain ' => ' Type // Function type | Type '(' Sep ( Type , ',' ) ')' // Type application | '(' Type ')' // Parens | ' unit ' | Sep ( Type , '*' ) // Tuples | Id | QId | TVar Domain ::= Type // Single argument | '(' Sep ( Type , ',' ) ')' // Multiple arguments The function type arrow associates to the right. Example, 'a => list ( 'a ) => ( int * list ( 'a ))","title":"Types"},{"location":"sophia_syntax/#statements","text":"Function bodies are blocks of statements , where a statement is one of the following Stmt ::= ' switch ' ' ( ' Expr ')' Block ( Case ) | ' if ' ' ( ' Expr ')' Block ( Stmt ) | ' elif ' ' ( ' Expr ')' Block ( Stmt ) | ' else ' Block ( Stmt ) | ' let ' LetDef | Using | Expr LetDef ::= Id Args [ ':' Type ] '=' Block ( Stmt ) // Function definition | Pattern '=' Block ( Stmt ) // Value definition Case ::= Pattern ' => ' Block ( Stmt ) | Pattern Block ( GuardedCase ) GuardedCase ::= '|' Sep1 ( Expr , ',' ) ' => ' Block ( Stmt ) Pattern ::= Expr if statements can be followed by zero or more elif statements and an optional final else statement. For example, let x : int = 4 switch ( f ( x )) None => 0 Some ( y ) => if ( y > 10 ) \"too big\" elif ( y < 3 ) \"too small\" else \"just right\"","title":"Statements"},{"location":"sophia_syntax/#expressions","text":"Expr ::= '(' LamArgs ')' ' => ' Block ( Stmt ) // Anonymous function (x) => x + 1 | '(' BinOp ')' // Operator lambda (+) | ' if ' ' ( ' Expr ')' Expr ' else ' Expr // If expression if(x < y) y else x | Expr ':' Type // Type annotation 5 : int | Expr BinOp Expr // Binary operator x + y | UnOp Expr // Unary operator ! b | Expr '(' Sep ( Expr , ',' ) ')' // Application f(x, y) | Expr '.' Id // Projection state.x | Expr '[' Expr ']' // Map lookup map[key] | Expr '{' Sep ( FieldUpdate , ',' ) '}' // Record or map update r{ fld[key].x = y } | '[' Sep ( Expr , ',' ) ']' // List [1, 2, 3] | '[' Expr '|' Sep ( Generator , ',' ) ']' // List comprehension [k | x <- [1], if (f(x)), let k = x+1] | '[' Expr ' .. ' Expr ']' // List range [1..n] | '{' Sep ( FieldUpdate , ',' ) '}' // Record or map value {x = 0, y = 1}, {[key] = val} | '(' Expr ')' // Parens (1 + 2) * 3 | '(' Expr '=' Expr ')' // Assign pattern (y = x::_) | Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token | Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, \"foo\", '%' | AccountAddress | ContractAddress // Chain identifiers | OracleAddress | OracleQueryId // Chain identifiers Generator ::= Pattern ' <- ' Expr // Generator | ' if ' ' ( ' Expr ')' // Guard | LetDef // Definition LamArgs ::= '(' Sep ( LamArg , ',' ) ')' LamArg ::= Id [ ':' Type ] FieldUpdate ::= Path '=' Expr Path ::= Id // Record field | '[' Expr ']' // Map key | Path '.' Id // Nested record field | Path '[' Expr ']' // Nested map key BinOp ::= ' || ' | ' && ' | '<' | '>' | ' =< ' | ' >= ' | ' == ' | ' != ' | ' :: ' | ' ++ ' | '+' | '-' | '*' | '/' | ' mod ' | '^' | ' |> ' UnOp ::= '-' | '!'","title":"Expressions"},{"location":"sophia_syntax/#operators-types","text":"Operators Type - + * / mod ^ arithmetic operators ! && || logical operators == != < > =< >= comparison operators :: ++ list operators |> functional operators","title":"Operators types"},{"location":"sophia_syntax/#operator-precedence","text":"In order of highest to lowest precedence. Operators Associativity ! right ^ left * / mod left - (unary) right + - left :: ++ right < > =< >= == != none && right || right |> left","title":"Operator precedence"}]}
\ No newline at end of file
diff --git a/master/sitemap.xml b/master/sitemap.xml
index c9956c2..8282a0c 100644
--- a/master/sitemap.xml
+++ b/master/sitemap.xml
@@ -2,47 +2,47 @@
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
None
- 2022-11-01
+ 2022-11-17
daily
\ No newline at end of file
diff --git a/master/sitemap.xml.gz b/master/sitemap.xml.gz
index 664a6e5..40bc0ab 100644
Binary files a/master/sitemap.xml.gz and b/master/sitemap.xml.gz differ
diff --git a/master/sophia_features/index.html b/master/sophia_features/index.html
index 4281f51..4e3c0f7 100644
--- a/master/sophia_features/index.html
+++ b/master/sophia_features/index.html
@@ -1190,6 +1190,16 @@ contract interface X : Z =
entrypoint y() = 1
entrypoint z() = 1
+Adding or removing modifiers
+When a contract
or a contract interface
implements another contract interface
, the payable
and stateful
modifiers can be kept or changed, both in the contract and in the entrypoints, according to the following rules:
+
+- A
payable
contract or interface can implement a payable
interface or a non-payable
interface.
+- A non-
payable
contract or interface can only implement a non-payable
interface, and cannot implement a payable
interface.
+- A
payable
entrypoint can implement a payable
entrypoint or a non-payable
entrypoint.
+- A non-
payable
entrypoint can only implement a non-payable
entrypoint, and cannot implement a payable
entrypoint.
+- A non-
stateful
entrypoint can implement a stateful
entrypoint or a non-stateful
entrypoint.
+- A
stateful
entrypoint can only implement a stateful
entrypoint, and cannot implement a non-stateful
entrypoint.
+
Subtyping and variance
Subtyping in Sophia follows common rules that take type variance into account. As described by Wikipedia,