# Chapter 15

You've come a long way from the first chapter! When you started, the stack was a mysterious land where unknown things happen. Now, it has no more secret for you and you manipulate its elements with ease. Congratulations!

For this chapter, we are going to explore a more advanced subject of the Michelson language: lambdas! Even if you don't know what lambdas are, if you have ever used a high-level programming language, you probably are familiar with a very similar concept: functions. You can imagine a lambda as a very simple function: a piece of Michelson code where you indicate the value you will put in and the value you expect out. The code inside the lambda will manipulate the expected input and return the expected output. Let's see a simple example to understand how it works:

parameter int ;
storage int ;
code {
    CAR ;
    LAMBDA int int { PUSH int 2 ; ADD } ;
    SWAP ;
    EXEC ;
    NIL operation ;
    PAIR
} ;

RUN %default 5 6 ;
stdout
parameter int; storage int; code { CAR ; LAMBDA int int { PUSH int 2 ; ADD } ; SWAP ; EXEC ; NIL operation ; PAIR }; RUN: use %default; drop all; push (5, 6); CAR: pop (5, 6); push 5; LAMBDA: push { PUSH int 2 ; ADD }; SWAP: pop { PUSH int 2 ; ADD }, 5; push { PUSH int 2 ; ADD }; push 5; EXEC: pop 5, { PUSH int 2 ; ADD }; PUSH: push 2; ADD: pop 2, 5; push 7; pop 7; push 7; NIL: push []; PAIR: pop [], 7; push ([], 7);
value type
7
int

This contract is pretty naive but it demonstrates well what lambdas do. From the LAMBDA int int { PUSH int 2 ; ADD } line, you understand that the lambda takes an int as an argument and returns an int. From the code between curly braces, you understand that int 2 is going to be pushed onto the stack and added to the parameter received by the lambda. Before we can execute the lambda, we have to make sure that the parameter it excepts is on top of it in the stack (that's the function of SWAP). Next, you can use the EXEC instruction to execute the lambda. The lambda will take its parameter, run it through the different steps of its code and output a value.

It is a very powerful pattern in order to avoid repeating the same piece of code that you need multiple times:

parameter (pair int int) ;
storage int ;
code {
    UNPPAIIR ;
    LAMBDA int int { PUSH int 2 ; ADD } ;
    SWAP ;
    DIP { DUP } ;
    EXEC ;
    SWAP ;
    DUP ;
    DIG 3 ;
    EXEC ;
    SWAP ;
    DIG 3 ;
    EXEC ;
    ADD ;
    ADD ;
    NIL operation ;
    PAIR
} ;

RUN %default (Pair 5 6) 7 ;
stdout
parameter (pair int int); storage int; code { { { DUP ; CAR ; DIP { CDR } } ; { DUP ; CAR ; DIP { CDR } } } ; LAMBDA int int { PUSH int 2 ; ADD } ; SWAP ; DIP { DUP } ; EXEC ; SWAP ; DUP ; DIG 3 ; EXEC ; SWAP ; DIG 3 ; EXEC ; ADD ; ADD ; NIL operation ; PAIR }; RUN: use %default; drop all; push ((5, 6), 7); DUP: push ((5, 6), 7); CAR: pop ((5, 6), 7); push (5, 6); DIP: protect 1 item(s); CDR: pop ((5, 6), 7); push 7; restore 1 item(s); DUP: push (5, 6); CAR: pop (5, 6); push 5; DIP: protect 1 item(s); CDR: pop (5, 6); push 6; restore 1 item(s); LAMBDA: push { PUSH int 2 ; ADD }; SWAP: pop { PUSH int 2 ; ADD }, 5; push { PUSH int 2 ; ADD }; push 5; DIP: protect 1 item(s); DUP: push { PUSH int 2 ; ADD }; restore 1 item(s); EXEC: pop 5, { PUSH int 2 ; ADD }; PUSH: push 2; ADD: pop 2, 5; push 7; pop 7; push 7; SWAP: pop 7, { PUSH int 2 ; ADD }; push 7; push { PUSH int 2 ; ADD }; DUP: push { PUSH int 2 ; ADD }; DIG: protect 3 item(s); pop 6; restore 3 item(s); push 6; EXEC: pop 6, { PUSH int 2 ; ADD }; PUSH: push 2; ADD: pop 2, 6; push 8; pop 8; push 8; SWAP: pop 8, { PUSH int 2 ; ADD }; push 8; push { PUSH int 2 ; ADD }; DIG: protect 3 item(s); pop 7; restore 3 item(s); push 7; EXEC: pop 7, { PUSH int 2 ; ADD }; PUSH: push 2; ADD: pop 2, 7; push 9; pop 9; push 9; ADD: pop 9, 8; push 17; ADD: pop 17, 7; push 24; NIL: push []; PAIR: pop [], 24; push ([], 24);
value type
24
int

This example uses the same lambda as before but this time, we reuse it 3 times with the 3 different int values provided in the contract (the two int values from the pair passed as a parameter and the int in the storage). 2 is added to each of these values before adding them together (24 is the result of (5 + 2) + (6 + 2) + (7 + 2)). This demonstrates how you can reuse the same piece of code in a lambda if it is needed multiple times.

NOTE

you wouldn't use this kind of pattern in a real-world situation and would prefer a loop structure to apply the same code to multiple values, for example with LOOP.

Lambdas can also be stored in storage values like pair or map, which makes it easy to pass them as parameters or store them to execute them later. Here is a first example with a lambda passed as a parameter:

parameter (pair int (lambda int int)) ;
storage int ;
code {
    CAR ;
    UNPAIR ;
    EXEC ;
    NIL operation ;
    PAIR
} ;

RUN %default (Pair 5 { PUSH int 3 ; ADD }) 0 ;
stdout
parameter (pair int (lambda int int)); storage int; code { CAR ; { DUP ; CAR ; DIP { CDR } } ; EXEC ; NIL operation ; PAIR }; RUN: use %default; drop all; push ((5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), 0); CAR: pop ((5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), 0); push (5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); DUP: push (5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); CAR: pop (5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); push 5; DIP: protect 1 item(s); CDR: pop (5, [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); push { PUSH int 3 ; ADD }; restore 1 item(s); EXEC: pop 5, { PUSH int 3 ; ADD }; PUSH: push 3; ADD: pop 3, 5; push 8; pop 8; push 8; NIL: push []; PAIR: pop [], 8; push ([], 8);
value type
8
int

You can see from this example that Michelson doesn't complain much about us passing a lambda as an argument 😊 It goes without saying that the lambda must be correct and fit with the state of the stack when you want to use it.

Let's save our lambda in a map and reuse it afterwards:

parameter (pair string (lambda int int)) ;
storage (map string (lambda int int)) ;
code {
    UNPPAIIR ;
    DUP ;
    DUG 3 ;
    DIP { SOME } ;
    UPDATE ;
    SWAP ;
    GET ;
    IF_NONE
        { FAIL }
        {
            PUSH int 7 ;
            EXEC ;
        } ;
    DROP ;
    PUSH (map string (lambda int int)) {} ;
    NIL operation ;
    PAIR ;
} ;

RUN %default (Pair "add3" { PUSH int 3 ; ADD }) {} ;
stdout
parameter (pair string (lambda int int)); storage (map string (lambda int int)); code { { { DUP ; CAR ; DIP { CDR } } ; { DUP ; CAR ; DIP { CDR } } } ; DUP ; DUG 3 ; DIP { SOME } ; UPDATE ; SWAP ; GET ; IF_NONE { { UNIT ; FAILWITH } } { PUSH int 7 ; EXEC } ; DROP ; PUSH (map string (lambda int int)) {} ; NIL operation ; PAIR }; RUN: use %default; drop all; push (('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), {}); DUP: push (('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), {}); CAR: pop (('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), {}); push ('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); DIP: protect 1 item(s); CDR: pop (('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]), {}); push {}; restore 1 item(s); DUP: push ('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); CAR: pop ('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); push add3; DIP: protect 1 item(s); CDR: pop ('add3', [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]); push { PUSH int 3 ; ADD }; restore 1 item(s); DUP: push add3; DUG: pop add3; protect 3 item(s); push add3; restore 3 item(s); DIP: protect 1 item(s); SOME: pop { PUSH int 3 ; ADD }; push ([{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}],); restore 1 item(s); UPDATE: pop add3, ([{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}],), {}; push {'add3': [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]}; SWAP: pop {'add3': [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]}, add3; push {'add3': [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]}; push add3; GET: pop add3, {'add3': [{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}]}; push ([{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}],); IF_NONE: pop ([{'prim': 'PUSH', 'args': [{'prim': 'int'}, {'int': '3'}]}, {'prim': 'ADD'}],); push { PUSH int 3 ; ADD }; PUSH: push 7; EXEC: pop 7, { PUSH int 3 ; ADD }; PUSH: push 3; ADD: pop 3, 7; push 10; pop 10; push 10; DROP: pop 10; PUSH: push {}; NIL: push []; PAIR: pop [], {}; push ([], {});
value type
{}
map string (lambda int int)

This unuseful contract gets a pair as parameter with the name of the lambda on the left as a string and the lambda on the right. The storage is a map whose keys are strings and values are lambdas. The contract unwraps the different pairs, duplicates the name of the lambda to find it later, saves it in the name, retrieves it and uses it before returning an empty map.

Note: saving lambdas in a big map (instead of a simple map) is a pattern used in production by tzBTC. This method allows to change the lambdas and thus the code of the contract. Although it seems like a good idea for upgradable contracts, it obfuscates the actual code and makes it harder to track changes and know what the code really does.

There is another instruction we can use with lambdas call APPLY. You will probably never use it and rarely see it used but it is worth knowing it exists. In a nutshell, the APPLY instruction adds two lines of code at the beginning of your lambda: one PUSH instruction that will push the current value between the APPLY instruction and the LAMBDA and one PAIR instruction that pairs the value added with PUSH and the parameter passed to the lambda. This kind of pattern can be interesting for lambdas to execute in iterating structures as demonstrated in the example below:

DEBUG False;

parameter int;
storage (list int);
code {
      UNPAIR @p @s ; # p :: s
      LAMBDA (pair int (pair int int)) int
             { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL }; # l :: p :: s
      SWAP ; 
      APPLY ; # l :: s
      PUSH int 3 ; 
      APPLY ; # l :: s
      SWAP ; 
      MAP 
          { DIP { DUP } ; EXEC } ; # s :: l
      DIP { DROP } ; # s
      NIL operation; 
      PAIR 
};

RUN %default 4 {1 ; 2 ; 3 ; 4} ;
value type
{ 7 ; 14 ; 21 ; 28 }
list int

The code for this example can be found here.

add add