Skip to content
On this page

Lambdas โ€‹

The type of functions in SmartPy is sp.TLambda(t1, t2, with_storage=None, with_operations=False) where t1 is the parameter type and t2 the result type; with_storage and with_operations are the lambda context parameters.

By default, lambdas have no effect or context (besides possibly failure) but it is often useful to introduce them.

Contexts โ€‹

The two possible context parameters are with_storage and with_operations.

  • with_storage="read-only" or with_storage="read-write", for functions that read or read-write the storage.
  • with_operations=True, for functions that create operations.

Intuitively, a lambda with a non-trivial context (with_storage and/or with_operations) is a regular lambda with:

  • an augmented type describing contextual use of storage and/or operations;
  • some code around its input (for storage) and/or output (for storage and/or operations) to take care of reading and writing needs.

The corresponding type in Michelson is

Michelson lambda.

See reference Lambdas template.

Operations โ€‹

Build a lambda โ€‹

sp.build_lambda(l,ย with_storage=None,ย with_operations=False,ย recursive=False)
Build a SmartPy lambda from a Python function or lambda.

  • with_storage="read-only" or with_storage="read-write", for functions that read or read-write the storage.

  • with_operations=True, for functions that create operations.

  • recursive=True, for recursive lambdas. A second parameter specifies the function name used for recursive calls, e.g.: sp.build_lambda((lambdaย x,ย f: ...f(x-1)....),ย recursive=True). Recursive lambdas cannot have storage or operations effects.

For example, sp.build_lambda(lambdaย x: x +ย 3) represents a function that takes an argument x and returns x +ย 3.
This function is usually useless as it is called automatically by SmartPy in most contexts.

Example โ€‹

python
# Explicit call
logic = sp.build_lambda(lambda x : x + 3)
x = logic(3); # A SmartPy expression that evaluates to 6

# sp.build_lambda is called automatically
# because it needs to be converted to a SmartPy expression
self.data.f = lambda x : x + 3

# This is regular Python
logic = lambda x : x + 3
x = logic(3); # 6

# Recursive factorial function
sp.build_lambda((lambda n, fact: sp.eif(n<=1, 1, n*fact(n-1))), recursive=True)
Michelson LAMBDAMichelson LAMBDA_REC

Define a private lambda โ€‹

@sp.private_lambda(with_storage=None,ย with_operations=False,ย wrap_call=False)
Decorator to introduce a lambda that is also a private variable.
This is used for functions that are expected to be used more than once.
Values are returned by using sp.result(value).

WARNING

Deprecated aliases

  • @sp.global_lambda is deprecated in favor of
python
@sp.private_lambda(with_storage=None, with_operations=False, wrap_call=False)
def f(self, params): # Please note that we need a self parameter here.
   ...
  • @sp.sub_entry_point is deprecated in favor of
python
@sp.private_lambda(with_storage="read-write", with_operations=True, wrap_call=True)
def f(self, params):
   ...

We have the usual parameters to describe the context plus wrap_call:

  • with_storage="read-only" or with_storage="read-write", for functions that read or read-write the storage.
  • with_operations=True, for functions that create operations.
  • wrap_call=True, resolves calls immediately (with an implicit sp.compute).
  • recursive=True, for recursive lambdas. A second parameter specifies the function name used for recursive calls (see example below).

Any combination of the parameters for sp.private_lambda(...) is allowed, but recursive=True excludes storage and operations effects.

See reference WorldCalculator template.

Example โ€‹

python
class MyContract(sp.Contract):
    # ...

    @sp.private_lambda()
    def transformer(self, x):
        sp.result(x + 5)

    @sp.private_lambda(with_operations=True, with_storage="read-write", wrap_call=True)
    def set_delegate(self):
        sp.set_delegate(sp.some(self.data.baker))

    @sp.entrypoint
    def ep(self, params):
        self.data.result = self.transformer(params)
        self.set_delegate() # wrap_call=True is necessary because "self.set_delegate()" result is not assigned to the storage or used in a later step

    # A recursive factorial function. You can also replace 'f' with 'factorial'.
    @sp.private_lambda(recursive=True)
    def factorial(self, n, f):
        sp.if n <= 1:
             sp.result(n)
        sp.else:
             sp.result(n * f(n-1))
Michelson LAMBDA

Calling lambdas โ€‹

f(x)
Call a lambda.

If f is of type sp.TLambda(t1, t2) and x is of type t1 then f(x) is of type t2.

Michelson EXEC

INFO

As for every SmartPy expression, simply writing y =ย f(x) doesn't directly compute f(x). It builds an expression that will be computed if used in some action so its output needs to be used or we need to wrap the call in some sp.compute(...).

f.apply(x)
Partially apply a lambda.

If f is of type sp.TLambda(sp.TPair(tp1, tp2), target) and x is of type tp1 then f.apply(x) is of type sp.TLambda(tp2, target).

Michelson APPLY