Slide 1

Slide 1 text

Никита Соболев github.com/sobolevn

Slide 2

Slide 2 text

>_ X Функциональное программирование для новичков

Slide 3

Slide 3 text

Проблемы определений

Slide 4

Slide 4 text

Проблемы определений > Функциональный стиль / императивный стиль

Slide 5

Slide 5 text

Проблемы определений > Функциональный стиль / императивный стиль > Способ проверки типов: до / во время работы

Slide 6

Slide 6 text

Проблемы определений > Функциональный стиль / императивный стиль > Способ проверки типов: до / во время работы > Изменяемые / неизменяемые структуры данных

Slide 7

Slide 7 text

Проблемы определений > Функциональный стиль / императивный стиль > Способ проверки типов: до / во время работы > Изменяемые / неизменяемые структуры данных > Поддержка языка

Slide 8

Slide 8 text

Проблемы определений > Функциональный стиль / императивный стиль > Способ проверки типов: до / во время работы > Изменяемые / неизменяемые структуры данных > Поддержка языка > Стиль для низкого уровня программирования

Slide 9

Slide 9 text

Но на самом деле!

Slide 10

Slide 10 text

def sum_numbers(numbers): ... def generate_numbers(count): ... print(sum_numbers(generate_numbers(5)))

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Композиция

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

❌ ❌

Slide 15

Slide 15 text

= типы

Slide 16

Slide 16 text

А что у нас с типизацией?

Slide 17

Slide 17 text

А что у нас с типизацией? > С попытками приведения / без console.log(1 + 'a')

Slide 18

Slide 18 text

А что у нас с типизацией? > С попытками приведения / без console.log(1 + 'a') > Проверка до выполнения / проверка во время выполнения

Slide 19

Slide 19 text

А что у нас с типизацией? > С попытками приведения / без console.log(1 + 'a') > Проверка до выполнения / проверка во время выполнения > Явные аннотации / скрытые типы

Slide 20

Slide 20 text

Явная типизация позволяет нам по одному объявлению функции узнать о ней все!

Slide 21

Slide 21 text

def sum_numbers(numbers): ... def generate_numbers(count): ... print(sum_numbers(generate_numbers(5)))

Slide 22

Slide 22 text

def sum_numbers(numbers: List[int]) -> int: ... def generate_numbers(count: int) -> List[int]: ... print(sum_numbers(generate_numbers(5)))

Slide 23

Slide 23 text

>_ X Практика

Slide 24

Slide 24 text

dry-python/returns Делаем неявное – явным 16 github.com/dry-python/returns

Slide 25

Slide 25 text

{"a": 1}.get(by_key)

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Input -> или

Slide 29

Slide 29 text

Result[, ] если = значение = ошибка

Slide 30

Slide 30 text

Maybe[] если = None

Slide 31

Slide 31 text

Callable[[List[int]], List[str]] 23

Slide 32

Slide 32 text

Callable[[List[int]], List[str]] • Выбросит ли она исключение? Да? Result[List[int], Exception] 23

Slide 33

Slide 33 text

Callable[[List[int]], List[str]] • Выбросит ли она исключение? Да? Result[List[int], Exception] • Является ли наша функция чистой? Нет? IO[List[int]] 23

Slide 34

Slide 34 text

Callable[[List[int]], List[str]] • Выбросит ли она исключение? Да? Result[List[int], Exception] • Является ли наша функция чистой? Нет? IO[List[int]] • Все вместе? Конечно! IOResult[List[int], Exception] 23

Slide 35

Slide 35 text

И более удобная композиция compose, pipe, flow, bind, pipeline, lift 24

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

= типы

Slide 38

Slide 38 text

27 def get_user(user_id: int) -> IOResultE['User']: return _parse_json(_make_request(user_id)) # BOOM def _make_request(user_id: int) -> IOResultE[Response]: ... def _parse_json(response: Response) -> ResultE['User']: ...

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

29 def get_user(user_id: int) -> IOResultE['User']: return IOResult.lift_result( _parse_json, )(_make_request(user)) def _make_request(user_id: int) -> IOResultE[Response]: ... def _parse_json(response: Response) -> ResultE['User']: ...

Slide 41

Slide 41 text

30 def get_user(user_id: int) -> IOResultE['User']: return flow( user_id, _make_request, IOResult.lift_result(_parse_json), ) @impure_safe def _make_request(user_id: int) -> Response: ... @safe def _parse_json(response: Response) -> 'User': ...

Slide 42

Slide 42 text

А что если функция зависит от текущего контекста? RequiresContext[Env, Result]

Slide 43

Slide 43 text

А что если функция асинхронная?

Slide 44

Slide 44 text

dry-python/returns Делаем неявное – явным 33 github.com/dry-python/returns

Slide 45

Slide 45 text

Полезные ссылки • https://sobolevn.me/2019/02/python-exceptions- considered-an-antipattern • https://sobolevn.me/2020/02/typed-functional- dependency-injection 34

Slide 46

Slide 46 text

t.me/ opensource_findings 35

Slide 47

Slide 47 text

Вопросы? github.com/sobolevn sobolevn.me 36