# 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 โ

```
# 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)
```

### 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

```
@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

```
@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 โ

```
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))
```

### 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`

.

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)`

.