# `lambda` expression

## No parameters

`lambda` expressions can be defined without any parameters.

```py
reveal_type(lambda: 1)  # revealed: () -> Unknown

# error: [unresolved-reference]
reveal_type(lambda: a)  # revealed: () -> Unknown
```

## With parameters

Unlike parameters in function definition, the parameters in a `lambda` expression cannot be
annotated.

```py
reveal_type(lambda a: a)  # revealed: (a) -> Unknown
reveal_type(lambda a, b: a + b)  # revealed: (a, b) -> Unknown
```

But, it can have default values:

```py
reveal_type(lambda a=1: a)  # revealed: (a=Literal[1]) -> Unknown
reveal_type(lambda a, b=2: a)  # revealed: (a, b=Literal[2]) -> Unknown
```

And, positional-only parameters:

```py
reveal_type(lambda a, b, /, c: c)  # revealed: (a, b, /, c) -> Unknown
```

And, keyword-only parameters:

```py
reveal_type(lambda a, *, b=2, c: b)  # revealed: (a, *, b=Literal[2], c) -> Unknown
```

And, variadic parameter:

```py
reveal_type(lambda *args: args)  # revealed: (*args) -> Unknown
```

And, keyword-varidic parameter:

```py
reveal_type(lambda **kwargs: kwargs)  # revealed: (**kwargs) -> Unknown
```

Mixing all of them together:

```py
# revealed: (a, b, /, c=Literal[True], *args, *, d=Literal["default"], e=Literal[5], **kwargs) -> Unknown
reveal_type(lambda a, b, /, c=True, *args, d="default", e=5, **kwargs: None)
```

## Parameter type

In addition to correctly inferring the `lambda` expression, the parameters should also be inferred
correctly.

Using a parameter with no default value:

```py
lambda x: reveal_type(x)  # revealed: Unknown
```

Using a parameter with default value:

```py
lambda x=1: reveal_type(x)  # revealed: Unknown | Literal[1]
```

Using a variadic parameter:

```py
lambda *args: reveal_type(args)  # revealed: tuple[Unknown, ...]
```

Using a keyword-variadic parameter:

```py
lambda **kwargs: reveal_type(kwargs)  # revealed: dict[str, Unknown]
```

## Nested `lambda` expressions

Here, a `lambda` expression is used as the default value for a parameter in another `lambda`
expression.

```py
reveal_type(lambda a=lambda x, y: 0: 2)  # revealed: (a=(x, y) -> Unknown) -> Unknown
```

## Assignment

This does not enumerate all combinations of parameter kinds as that should be covered by the
[subtype tests for callable types](./../type_properties/is_subtype_of.md#callable).

```py
from typing import Callable

a1: Callable[[], None] = lambda: None
a2: Callable[[int], None] = lambda x: None
a3: Callable[[int, int], None] = lambda x, y, z=1: None
a4: Callable[[int, int], None] = lambda *args: None

# error: [invalid-assignment]
a5: Callable[[], None] = lambda x: None
# error: [invalid-assignment]
a6: Callable[[int], None] = lambda: None
```

## Function-like behavior of lambdas

All `lambda` functions are instances of `types.FunctionType` and should have access to the same set
of attributes.

```py
x = lambda y: y

reveal_type(x.__code__)  # revealed: CodeType
reveal_type(x.__name__)  # revealed: str
reveal_type(x.__defaults__)  # revealed: tuple[Any, ...] | None
reveal_type(x.__annotations__)  # revealed: dict[str, @Todo(Support for `typing.TypeAlias`)]
reveal_type(x.__dict__)  # revealed: dict[str, Any]
reveal_type(x.__doc__)  # revealed: str | None
reveal_type(x.__kwdefaults__)  # revealed: dict[str, Any] | None
reveal_type(x.__module__)  # revealed: str
reveal_type(x.__qualname__)  # revealed: str
```
