4.2 KiB
id | title |
---|---|
functions | Functions |
Writing code is fun as long as it doesn't get out of hand. To make sure our code doesn't turn into spaghetti we can group some logic into functions.
Instruction blocks
With block
(s) you can wrap instructions and expressions into an isolated scope.
Each block
needs to include at least one instruction
, or a placeholder instruction called skip
.
// shorthand syntax
block { a := a + 1 }
// verbose syntax
begin
a := a + 1
end
Defining a function
Functions in PascaLIGO are defined using the function
keyword
followed by their name
, parameters
and return
type definitions.
Here's how you define a basic function that accepts two int
s and
returns a single int
:
function add(const a: int; const b: int): int is
begin
const result: int = a + b;
end with result;
The function body consists of two parts:
block {<code>}
- logic of the functionwith <value>
- the return value of the function
Blockless functions
Functions that can contain all of their logic into a single
instruction/expression, can be defined without the surrounding
block
. Instead, you can inline the necessary logic directly, like
this:
function add(const a: int; const b: int): int is a + b
Functions in CameLIGO are defined using the let
keyword, like value
bindings. The difference is that after the value name a list of
function parameters is provided, along with a return type.
CameLIGO is a little different from other syntaxes when it comes to function parameters. In OCaml, functions can only take one parameter. To get functions with multiple arguments like we are used to in traditional programming languages, a technique called currying is used. Currying essentially translates a function with multiple arguments into a series of single argument functions, each returning a new function accepting the next argument until every parameter is filled. This is useful because it means that CameLIGO can support partial application.
Currying is however not the preferred way to pass function arguments in CameLIGO. While this approach is faithful to the original OCaml, it's costlier in Michelson than naive function execution accepting multiple arguments. Instead for most functions with more than one parameter we should place the arguments in a tuple and pass the tuple in as a single parameter.
Here is how you define a basic function that accepts two ints
and
returns an int
as well:
let add (a,b: int * int) : int = a + b
let add_curry (a: int) (b: int) : int = a + b
The function body is a series of expressions, which are evaluated to give the return value.
Functions in ReasonLIGO are defined using the let
keyword, like
value bindings. The difference is that after the value name a list of
function parameters is provided, along with a return type.
Here is how you define a basic function that accepts two int
s and
returns an int
as well:
let add = ((a,b): (int, int)) : int => a + b;
The function body is a series of expressions, which are evaluated to give the return value.
Anonymous functions
Functions without a name, also known as anonymous functions are useful in cases when you want to pass the function as an argument or assign it to a key in a record or a map.
Here's how to define an anonymous function assigned to a variable
increment
, with it is appropriate function type signature.
const increment : int -> int = function (const i : int) : int is i + 1;
// a = 2
const a: int = increment (1);
let increment : int -> int = fun (i: int) -> i + 1
let increment: (int => int) = (i: int) => i + 1;