Expressions

Indigo has several builders of expressions (here generically called operators) and statements employing them. This appendix is meant to list the former and present the latter.

This will not explain the basics of expressions, because this is already the argument of some tutorial's chapters. In particular, if you haven't already, please read the tutorial's chapter about Expressions and operators.

As a reminder, for informations on types you can instead consult their reference material.

Consulting the operators' tables

All operators listed in the following tables can have a certain amount of argument expressions and will always return a single resulting expression.

As a reminder the most basic expressions are the constant ones, for example you can write True or 42 int in your contract code and know that these are expressions of type Bool or Integer, respectively.

Much like constants some of the following operators can be used on their own, because they have no inputs. For example, sender takes no arguments and is an expression of type Address.

However most operators have one or more inputs, in which case you can use them by writing the operator followed by its arguments, each separated by spaces. For example, these are valid expressions:

  • abs (1 int) (abs takes 1 argument expression of type Integer)
  • pair () True (pair takes 2 of any type instead)

Infix operators are all the ones that take 2 arguments and are made of symbols (as opposed to letters) and as such they are used between their arguments and not before them (e.g. 1 + 2, True || False, etc.)

Many infix operator have a synonym prefix form, in which case you'll find them specified in the same row (e.g. add and +).

Compound operators are also infix, but are special in that they:

  1. do require the first argument to be a variable
  2. will replace the value of the variable with the result of the expression
  3. do not return an expression, but a complete statement For example:
1 int += 2 int -- is invalid, this will not compile

a <- new$ 1 int
a += 2 int -- "a" will have value of "3" after this expression

b <- new$ a += 1 int -- is also invalid, because "(a += b)" is not an expression

Type variables are used in the types of these tables as well, you can recognize them because they start with a lower-case letter.

Unless differently specified, they can be replaced by any other type, however remember that if the same variable is used in a line this means its type is the same everywhere it is used.

For example, if an operator says to accept an expression of type [a] as an input and return one of type a, it means it can operate on a list of any type and will return a single element, but of that same type (e.g. take a [Integer] and return an Integer, or a [Natural] and return a Natural, but not take [Integer] and return a Natural).

You'll notice also that some operators are overloaded, so you'll find them in multiple places, operating on and returning different types. For example you can sum 2 Naturals with + as well as 2 Integers.

Logical sections

Starting right below are the operators and statements for Indigo.

They are grouped in sections based on the logic they execute.

Arithmetic

Operators

Operator Infix Input type I Input type II Result type Compound Description
add + Natural Integer Integer Sums the two values
add + Integer Natural Integer += Sums the two values
add + Natural Natural Natural += Sums the two values
add + Integer Integer Integer += Sums the two values
add + Timestamp Integer Timestamp += Increments/decrements the Timestamp by the given number of seconds
add + Integer Timestamp Timestamp Increments/decrements the Timestamp by the given number of seconds
add + Mutez Mutez Mutez += Sums the two values
sub - Natural Integer Integer Subtracts the second value from the first
sub - Integer Natural Integer -= Subtracts the second value from the first
sub - Natural Natural Integer Subtracts the second value from the first
sub - Integer Integer Integer -= Subtracts the second value from the first
sub - Timestamp Integer Timestamp -= Subtracts a number of seconds from the Timestamp
sub - Timestamp Timestamp Integer Subtracts the second value from the first
sub - Mutez Mutez Mutez -= Subtracts the second value from the first
mul * Natural Integer Integer Multiplies the two values
mul * Integer Natural Integer *= Multiplies the two values
mul * Natural Natural Natural *= Multiplies the two values
mul * Integer Integer Integer *= Multiplies the two values
mul * Natural Mutez Mutez Multiplies the two values
mul * Mutez Natural Mutez *= Multiplies the two values
div / Integer Integer Integer Divides the first value by the second
div / Integer Natural Integer Divides the first value by the second
div / Natural Integer Integer Divides the first value by the second
div / Natural Natural Natural Divides the first value by the second
div / Mutez Mutez Natural Divides the first value by the second
div / Mutez Natural Mutez Divides the first value by the second
mod % Integer Integer Natural Modulo of the first value by the second
mod % Integer Natural Natural Modulo of the first value by the second
mod % Natural Integer Natural Modulo of the first value by the second
mod % Natural Natural Natural Modulo of the first value by the second
mod % Mutez Mutez Mutez Modulo of the first value by the second
mod % Mutez Natural Mutez Modulo of the first value by the second
neg Integer Integer Negates the input value
neg Natural Integer Negates the input value
abs Integer Natural Absolute value of the input

Comparison

NOTE: the comparable type variable in this section can be replaced only by a type that can be compared and not any arbitrary type, for more information see tezos's documentation.

Operators

Operator Infix Input type I Input type II Result type Description
eq == comparable comparable Bool Equal to
neq /= comparable comparable Bool Not equal to
le <= comparable comparable Bool Less than or equal to
ge >= comparable comparable Bool Greater than or equal to
lt < comparable comparable Bool Less than
gt > comparable comparable Bool Greater than

Bits and boolean

Operators

Operator Infix Input type I Input type II Result type Compound Description
lsl <<< Natural Natural Natural <<<= Bitwise left shift
lsr >>> Natural Natural Natural >>>= Bitwise right shift
and && Integer Natural Natural Bitwise and
and && Natural Natural Natural &&= Bitwise and
and && Bool Bool Bool &&= Boolean and
or || Natural Natural Natural ||= Bitwise or
or || Bool Bool Bool ||= Boolean or
xor ^ Natural Natural Natural ^= Bitwise xor
xor ^ Bool Bool Bool ^= Boolean xor
not Integer Integer Bitwise complement
not Natural Integer Bitwise complement
not Bool Bool Boolean not

Serialization

Operators

Operator Input type I Result type Description
pack any ByteString Serializes a piece of data to its binary representation
unpack ByteString Maybe any Returns some deserialized piece of data if valid, none otherwise

Pairs

Operators

Operator Input type I Input type II Result type Description
pair a b (a, b) Constructs a pair of values
car (a, b) a Extracts the left-side value from a pair. Synonym of fst.
cdr (a, b) b Extracts the right-side value from a pair. Synonym of snd.
fst (a, b) a Extracts the left-side value from a pair. Synonym of car.
snd (a, b) b Extracts the right-side value from a pair. Synonym of cdr.

Maybe

Operators

Operator Input type I Result type Description
some a Maybe a Wraps a value in a some
none Maybe a Creates a none

Either

Operators

Operator Input type I Result type Description
right a Either b a Wraps a value in a right
left b Either b a Wraps a value in a left

Conversion

Operators

Operator Input type I Result type Description
isNat Integer Maybe Natural Converts an Integer to some Natural if possible, none otherwise
toInt Natural Integer Converts a Natural to an Integer
nonZero Integer Maybe Integer Returns some of the given value if it is not 0, none otherwise.
nonZero Natural Maybe Natural Returns some of the given value if it is not 0, none otherwise.

Bytes and String

Operators

Operator Infix Input type I Input type II Result type Description
slice (Natural, Natural) MText Maybe MText Returns some sub-string by the given (offset, length) pair if one exists, none otherwise
slice (Natural, Natural) ByteString Maybe ByteString Returns some sub-bytestring by the given (offset, length) pair if one exists, none otherwise
concat <> MText MText MText String concatanation, the first value is pre-pended to the second one
concat <> ByteString ByteString ByteString Byte-strings concatanation, the first value is pre-pended to the second one

List

Operators

Operator Infix Input type I Input type II Result type Description
cons .: a [a] [a] Prepends/cons the given value to the given list
concatAll [MText] MText Concatenates all the strings in the list into a single one
concatAll [ByteString] ByteString Concatenates all the bytestrings in the list into a single one
size [a] Natural Returns the size of the given list
nil [a] Creates an empty list

Set

Operators

Operator Input type I Input type II Result type Description
!: Set a (a, Bool) Set a If the Bool is True it inserts the given value in the set, otherwise it remove it.
+: Set a a Set a Inserts the given value into the set
-: Set a a Set a Removes the given value from the set
?: Set a a Bool Checks for the presence of the given value in the set
update (a, Bool) Set a Set a If the Bool is True it inserts the given value in the set, otherwise it remove it.
insert a Set a Set a Inserts the given value into the set
remove a Set a Set a Removes the given value from the set
mem a Set a Bool Checks for the presence of the given value in the set
size Set a Natural Returns the size of the given set
empty Set a Creates an empty set
emptySet Set a Alias for empty to resolve ambiguousness in some cases

Map

Operators

Operator Input type I Input type II Result type Description
#: Map k v k Maybe v Looks up the key in the map and returns its value in some if found, none otherwise
!: Map k v (k, Maybe v) Map k v Updates the value associated to a key in a map. Inserts/replaces it with a value in some or removes it with none.
+: Map k v (k, v) Map k v Inserts the value associated to a key in a map. If there was one already, this gets overridden
-: Map k v k Map k v Removes the value associated to a key in a map
?: Map k v k Map k v Checks for the presence of the given key in the map
get k Map k v Maybe v Looks up the key in the map and returns its value in some if found, none otherwise
update (k, Maybe v) Map k v Map k v Updates the value associated to a key in a map. Inserts/replaces it with a value in some or removes it with none.
insert (k, v) Map k v Map k v Inserts the value associated to a key in a map. If there was one already, this gets overridden
remove k Map k v Map k v Removes the value associated to a key in a map
mem k Map k v Bool Checks for the presence of the given key in the map
size Map k v Natural Returns the size of the given map
empty Map k v Creates an empty map
emptyMap Map k v Alias for empty to resolve ambiguousness in some cases

BigMap

Operators

Operator Input type I Input type II Result type Description
#: BigMap k v k Maybe v Looks up the key in the bigMap and returns its value in some if found, none otherwise
!: BigMap k v (k, Maybe v) BigMap k v Updates the value associated to a key in a bigMap. Inserts/replaces it with a value in some or removes it with none.
+: BigMap k v (k, v) BigMap k v Inserts the value associated to a key in a bigMap. If there was one already, this gets overridden
-: BigMap k v k BigMap k v Removes the value associated to a key in a bigMap
?: BigMap k v k BigMap k v Checks for the presence of the given key in the bigMap
get k BigMap k v Maybe v Looks up the key in the bigMap and returns its value in some if found, none otherwise
update (k, Maybe v) BigMap k v BigMap k v Updates the value associated to a key in a bigMap. Inserts/replaces it with a value in some or removes it with none.
insert (k, v) BigMap k v BigMap k v Inserts the value associated to a key in a bigMap. If there was one already, this gets overridden
remove k BigMap k v BigMap k v Removes the value associated to a key in a bigMap
mem k BigMap k v Bool Checks for the presence of the given key in the bigMap
size BigMap k v Natural Returns the size of the given bigMap
empty BigMap k v Creates an empty bigMap
emptyBigMap BigMap k v Alias for empty to resolve ambiguousness in some cases

Record

Operators

Operator Input type I Input type II Result type Description
!! record (Label, field) record Sets the record field for the given Label to the given value
#! record Label field Retrieves the value associated with the given Label from the record
name Label field record Creates a record with one field, set to the given value, associated with the given Label
unName Label record field Retrieves the value associated with the given Label from the record that has only one field
!~ field Label record Creates a record with one field, set to the given value, associated with the given Label
#~ record Label field Retrieves the value associated with the given Label from the record that has only one field
construct (record, record, ...) record Creates a bigger record starting from a tuple of smaller ones

Auxiliary

Operators

Operator Input type I Input type II Input type III Result type Description
checkSignature PublicKey Signature ByteString Bool Checks that the given bytestring has been signed the given key
blake2b ByteString ByteString Returns the cryptographic hash of the given value using the blake2b hash function
sha256 ByteString ByteString Returns the cryptographic hash of the given value using the sha256 hash function
sha512 ByteString ByteString Returns the cryptographic hash of the given value using the sha512 hash function
hashKey PublicKey KeyHash Returns the b58check of the public key
now Timestamp The current time
amount Mutez Amount of the current transaction
sender Address Address that initiated the current transaction
chainId ChainId The chain identifier
balance Mutez Current balance held by the executing contract

Contract

As a reminder chapter 05 explains and shows with an example how to use the result of the following operators and statements to perform side effects.

Operators

Operator Input type I Result type Description
contract Address Maybe (ContractRef param) Casts the address to some ContractRef param if possible, none otherwise
implicitAccount KeyHash ContractRef () Returns a default contract with the given public/private key pair, which cannot execute code
contractAddress ContractRef p Address Cast the given ContractRef param to its Address
contractCallingString MText Address Make an unsafe reference to a contract from the given entrypoint
self ContractRef param ContractRef param of the current contract

Statements

For improved type safety Indigo internally uses some types in addition to Address and ContractRef param (the only ones listed in Appendix A: types).

Among these types the only one necessary to use the following statements is EntrypointRef mname. As the name might suggest this is an identifier for the entrypoint we want to call, there are two possibile choices for it: - CallDefault for the default entrypoint of a contract - Call @"<entrypointname>" where <entrypointname> is the name of the entrypoint we want to call

selfCalling is a statement that returns a ContractRef param variable given an EntrypointRef mname for the contract is executed in. For example, supposing we want to use this statement in the example controlContract of chapter 03, which defines its parameter type IncrementIf with entrypoints IsZero and HasDigitOne, each of the following is a valid use:

contractRef <- selfCalling CallDefault
contractRef <- selfCalling Call @"IsZero"
contractRef <- selfCalling Call @"HasDigitOne"

contractCalling is just like selfCalling, except it points at a different contract and because of this it also needs an expression for its address. For example, supposing this time we want to call the controlContract above from a different one (and that we already have a ccAddr variable for it), each of the following is a valid use:

mContractRef <- contractCalling CallDefault ccAddr
mContractRef <- contractCalling (Call @"IsZero") ccAddr
mContractRef <- contractCalling (Call @"HasDigitOne") ccAddr

Note that another difference with selfCalling is that it returns Maybe (ContractRef param) because it may fail to lookup the contract and return none.

views and voids

Operators

Operator Input type I Input type II Result type Description
makeView a ContractRef param View a param Creates a View entrypoint parameter
makeVoid a Lambda param param Void_ a param Creates a Void_ entrypoint parameter

Statements

The view_ statement allows to implement a View entrypoint by using a function. For example, let's say we have a contract that takes a View Integer Bool param for an entrypoint we could implement it like this:

  -- previous contract code to select the entrypoint
  view_ greaterThan0 param

greaterThan0 :: Var Integer -> IndigoFunction Bool
greaterThan0 val = defFunction do
  return (val >. 0 int)

As you can see we only need the function to take an Integer as parameter and return a Bool to satisfy the View Integer Bool requirement.

Another way to do so is by using the project statements, which is like view_ with the arguments inverted. This may seem pointless, but allows to define the function in place, so the previous example could be written as:

  -- previous contract code to select the entrypoint
  project param $ \val ->
    return (val > 0 int)

This is more compact and does not require the definition of a specific function.

Just like for Views there are statements for Voids that work in a matching way to the ones above: void_ and projectVoid.

Conditional

Statements

The most common conditional statement is the if ... then ... else ... construct. This specifies two branches of code to execute based on a Bool condition. Note that the branches can return a value, in which case this can be captured as a variable, but both branches need to return the same type. For example, these are valid statements:

if 1 int <= 2 int
  then do
    storage =: 1 int -- this will be executed
    return ()
  else do
    return () -- this will not

resVal <- if 1 int == 2 int
            then do
              return False
            else do
              a <- new$ 1 int == 1 int
              return a
-- we can now use the `resVal` `Bool` variable

From the first example statement above you can see than in its second branch we do not do anything (return ()), for these cases Indigo has a convenience statement called when that only takes the Bool condition and a single branch, that will be executed only if the condition is True. The first statement above could so be rewritten as:

when (1 int <= 2 int) do
  storage =: 1 int

In other cases we might want to do exactly the opposite and execute some code only when a Bool condition is False. Indigo has a convenience statement for this too, called unless. The previous example for instance could also be written as:

unless (1 int > 2 int) do
  storage =: 1 int

When we have to deal with Maybe as we often want to know if they are some a or none and execute a different code in each case. For this reason Indigo has the ifSome statement, that based on a Maybe a it executes one of its two branches. The first branch is executed in case the value is some a and takes that a as an input, the second one takes no input and is executed if the value is none For example, let's suppose to have a val variable containing some 1 of type Maybe Integer, these would be a valid statement:

ifSome val
    (\n -> storage =: n)
    (return ())

Just as for if we can have both branches return a value and assign it to a variable.

We have the reverse of ifSome as well, ifNone, whose first branch is executed only when the value is none and second branch is executed in case the value issome a and takes that a as an input.

We also two have statements similar to when for convenience: - whenSome whose single branch is executed only if the value is some a - whenNone whose single branch is executed only if the value is none

Similar to Maybe we also have conditional statement that work with Either as well: - ifRight whose: - first branch is executed only if the value is right a and takes a as input - second branch is executed in case the value is left b and takes b as an input - ifLeft which is the reverse of ifRight - whenRight whose single branch is executed only if the value is right a - whenLeft whose single branch is executed only if the value is left b

We also have another conditional statement that works with List a which is ifCons whose: - first branch is executed only if the value is not an empty list and takes the first element a and the rest of the elements List a as inputs - second branch is executed only if the value is an empty list

Loop

Statements

while is the statement that will execute a piece of code as long as a Bool condition holds. For example, this loop would execute twice:

i <- new$ 0 int
while (i int < 2 int) do
  -- more code can be here
  i += 1 int
-- the code following will get executed after the loop
i =: 0 int

whileLeft is another statement that will execute a function as long as the condition is a Left a and the function will take a as the argument. The statement will exit the loop when the condition is a Right b and return the b as the result.

forEach is instead a way to execute a piece of code over each of the elements of a container (a list, set or map). For example, given a numList variable of type [Integer] this will compute the sum of all its elements:

sum <- new$ 0 int
forEach numList $ \number -> do
  sum += number

Case

Statements

case_ is the statement that allows use to pattern-match on the constructors of a custom data-type to execute a different piece of code depending on the value of an expression.

To know about what types case_ can be used with, please refer to the types reference page. An example of a valid type and case_ usage can be found in the Tutorial's statements chapter.