Functions and Procedures¶
To promote reusability, readability and separation of code, Indigo supports functions and procedures. This chapter shows the syntax and expands on their usage.
Granular control¶
This chapter's source file is Functions.hs
, that contains functionsContract
:
module Indigo.Tutorial.Functions.Functions
( functionsContract
) where
import Indigo
data IncrementIf
= IsZero Integer
| HasDigitOne Natural
deriving stock (Generic, Show)
deriving anyclass (IsoValue)
instance ParameterHasEntrypoints IncrementIf where
type ParameterEntrypointsDerivation IncrementIf = EpdPlain
functionsContract :: IndigoContract IncrementIf Natural
functionsContract param = defContract do
result <- case_ param $
( #cIsZero #= checkZero
, #cHasDigitOne #= checkHasDigitOne
)
updateStorage result
checkZero :: Var Integer -> IndigoFunction Bool
checkZero val = defFunction do
return (val == 0 int)
checkHasDigitOne :: Var Natural -> IndigoFunction Bool
checkHasDigitOne val = defFunction do
base <- new$ 10 nat
checkRes <- new$ False
while (val > base && not checkRes) do
val =: val / base
remainder <- new$ val % base
checkRes =: remainder == 1 nat
return checkRes
updateStorage :: HasStorage Natural => Var Bool -> IndigoProcedure
updateStorage result = defFunction do
if result then storage =: 0 nat else incrementStorage
incrementStorage :: HasStorage Natural => IndigoProcedure
incrementStorage = defFunction do
storage += 1 nat
storage :: HasStorage Natural => Var Natural
storage = storageVar
When converted to Michelson this program is equivalent to the controlContract
from the previous chapter.
The difference is fully visible, in that the contract itself is much easier to read because it has been broken down into simple functions.
Let's look at their definition, starting from the first one:
checkZero :: Var Integer -> IndigoFunction Bool
checkZero val = defFunction do
return (val == 0 int)
This function takes the place of the code-block we used to execute in the first
pattern-match in controlContract
, that looked like this:
( #cIsZero #= \val -> do
return (val == 0 int)
As you can see this is almost identical to the checkZero
function's code.
The main difference is that we put val
before an =
and used defFunction
,
this should be easy to figure out, because defFunction
is to functions what
defContract
is to ... contracts, as you can see from the first lines here:
functionsContract param = defContract do
checkZero val = defFunction do
The other difference is that by using functions we need to explicitly write a
signature, but this is not hard, we can see that the ones for checkZero
is:
checkZero :: Var Integer -> IndigoFunction Bool
Just as we did in the Basics and Variables chapter for contracts, we can use a formula to make function signatures:
<function_name> :: [Var parameter ->] IndigoFunction <return_type>
Here's what you need to know:
- there can be 0 parameters as well as more than one.
- The return type can be any of the supported types.
In addition to this there are IndigoProcedure
s, that are just like
IndigoFunction
s, differing only by the absence of a return value (or in other
terms, they return ()
) and in fact begin with the same defFunction
.
That's it, quite simple isn't it?
This file also contains examples of Indigo functions with no parameters
(e.g. incrementStorage
), multiple parameters (e.g. checkHasDigitOne
) and
that access the storage (e.g. incrementStorage
, note that just like storage
these need to specify the correct HasStorage
constraint).
You can define such Indigo functions and call them in different places, also note that just like the other imperative constructs they have (automatically managed) scope.
Now that we are armed with functions as well we can proceed to the next chapter: Side Effects and Errors.
Technical details: defFunction and defContract¶
As for IndigoContract
s, both IndigoProcedure
s and IndigoFunction
s are just
specialized versions of IndigoM
.
These types are all connected and exist mostly for convenience. The same can be
said for defContract
which is just a specialized version of defFunction
that
carries on all the required constraints.
defFunction
is what makes this possible, as it adds scope management to the
given arbitrary IndigoM
, using the same logic mentioned in the previous chapter
for imperative statements.
You can find the definitions for all of these types and functions in the
Indigo.Compilation
and Indigo.Frontend.Language
modules.