functional patterns - dotnetconf'11

63
Теории и практики функционального программирования Акуляков Артём СИБИНФОСОФТ 11-я конференция .NET разработчиков 31 октября 2015 dotnetconf.ru

Upload: 0xffaa

Post on 22-Jan-2017

576 views

Category:

Engineering


6 download

TRANSCRIPT

Теории и практики функционального программирования

Акуляков АртёмСИБИНФОСОФТ

11-я конференция .NET разработчиков31 октября 2015dotnetconf.ru

Кто я?/ 5+ лет dotNet interpraise

/ 2+ лет python freelance

/ 2+ I love FP

2

К ЧЕМУ ЭТО ВСЕ?

3

Слишком часто слышно...

- я боюсь функционального программирования!

4

Поговорим об ООП

5

ООП против ФП

6

SOLID

IoC

GRASP

GangOfFour

MVC, MVP, MVVM

CQRS

EventSourcing

DDD

...

ООП против ФП

SOLID

IoC

GRASP

GangOfFour

MVC, MVP, MVVM

CQRS

EventSourcing

DDD

...

Functions

Type

Composition

7

Основы функционального программирования

8

Функции это тоже значения

9

Функции это тоже значения

let getCalc f x y = fun z -> (f x) + y + z

let calc = getCalc toX10 1 2

let result = calc value

10

Композиция

11

Композиция : функции

let read (x : string) : int = int(x)

let mult (x : int) : int = x * x

let write (x : int) : string = string(x)

12

Композиция : функции

let readMultWrite1 x = write (mult (read x))

// x : string -> string

let readMultWrite2 = read >> mult >> write

// string -> string

13

Композиция

a → b » b → ca → c

14

Композиция#большекомпозиции

a → b » b → c » ... » x → za → z

15

Композиция : функции#операторыкомпозиции

let (>>) f1 f2 = fun p -> f1 f2 plet (<<) f1 f2 = fun p -> f2 f1 p

16

ПРОБЛЕМА: Оператор композиции определен только для функций с

одним аргументом

17

РЕШЕНИЕ: Все функции это на самом деле функции от одного

аргумента

18

Композиция : функции #каррирование

let add x y = x + y // int -> int -> int

let add2 = add 2 // int -> int

let res = add2 2 // val res : int = 4

19

Композиция : функции#операторыкомпозиции

let (>>) f1 f2 p = f2(f1 p)let (<<) f1 f2 p = f1(f2 p)

20

Типы

21

Типы#обзор

type DiscriminatedUnion = | Variant1 of int | Variant2 of string

22

Композиция : типы

type LevelName = stringtype UID = int

type HierarchyIdentifier = | Plain of UID | Complex of LevelName*HierarchyIdentifier

23

Композиция : типы

Complex(LevelName * Complex

(LevelName * (Plain)

))

24

ООП и ФП имеют много общих концепций

25

DI

public class BasketCostTranslator : IBasketCostTranslator{ private readonly IExchangeRateProvider _provider;

public BasketCostTranslator(IExchangeRateProvider p) { // =) }

public BasketCost TranslateCost(BasketCost cost, Currency currency) { // =) }}

26

DI#кариррованиекакdi

type ICostTranslator = BasketCost -> BasketCost

let costTranslator exchangeProvider currency basket = // =)

let translator = costTranslator cbeRateProviderlet toUsdTranslator = translator Currency.USD

27

DI#кариррованиекакdi

type ICostTranslator = BasketCost -> BasketCost

let costTranslator exchangeProvider currency basket = // =)

let translator = costTranslator cbeRateProviderlet toUsdTranslator = translator Currency.USD

28

DI#кариррованиекакdi

type ICostTranslator = BasketCost -> BasketCost

let costTranslator exchangeProvider currency basket = // =)

let translator = costTranslator cbeRateProviderlet toUsdTranslator = translator Currency.USD

29

DI#кариррованиекакdi

type ICostTranslator = BasketCost -> BasketCost

let costTranslator exchangeProvider currency basket = // =)

let translator = costTranslator cbeRateProviderlet toUsdTranslator = translator Currency.USD

30

Кое-что интересное из мира ФП

31

Мемоизация

32

Мемоизация#чистыефункции

Чистая функция– детерминированная– без побочных эффектов

33

Мемоизация#чистыефункции

let add100 x = x + 100

add100 10 // val it : int = 110add100 10 // val it : int = 110add100 20 // val it : int = 120

34

Мемоизация#ультракеширование

let memoize (f: 'a -> 'b) = let dict = new Dictionary<'a, 'b>() let memoized (input: 'a) = match dict.TryGetValue(input) with | true, x -> x | false, _ -> let result = f input dict.Add(input, result) result memoized

let memAdder = memoize adder

35

Мемоизация#ультракеширование

let memoize (f: 'a -> 'b) = let dict = new Dictionary<'a, 'b>() let memoized (input: 'a) = match dict.TryGetValue(input) with | true, x -> x | false, _ -> let result = f input dict.Add(input, result) result memoized

let memAdder = memoize adder

36

Что не так с обычным кэшированием?

● Кэш устарел, а данные не изменились– Лишняя нагрузка

● Данные изменились, а кэш еще нет– Пользователи видят неактуальные данные

37

Мемоизация#вебприложение

HttpRequest → HttpResponse

38

Мемоизация#какчистаяфункция

function (HttpRequest) → HttpResponse

39

Мир неидеален

40

Мемоизация#всеравночистаяфункция

function (HttpRequest, DbState) → HttpResponse

41

Мемоизация#практика

https://github.com/Suor/django-cacheops

42

Сухой итог

● Функциональное программирование это просто● Можно использовать привычные приемы, но

проще● Можно заимствовать из функционального

программирования хитрые приемы

43

Полезности

http://www.intuit.ru/studies/courses/471/327/info

https://github.com/fsprojects/FSharpx.Extras

https://github.com/jack-pappas/ExtCore/

http://fsharpforfunandprofit.com/

44

Спасибо за вниманиеВопросы?

Акуляков АртёмСИБИНФОСОФТ

[email protected]/oxffaa

Обработка ошибок

46

Что не так с обычной обработкой ошибок?

Исключения прекрасны, но велик соблазн «логики на исключениях»

47

Обработка ошибок #идеальныймир

let handleRequest = readRequest >> readEntityFromDB >> modifyEntity >> createTaskFromEntity >> writeTaskToMQ >> createResultMessage >> sendMessage

48

49

Мир неидеален

Обработка ошибок

type Result<'r> = | Success of 'r | Error

// 'r -> Result<'r>

50

Обработка ошибок let handleRequest s = match readRequest s with | Success r -> match readEntityFromDB r with | Success e -> match modifyEntity e with | Success me -> match createTaskFromEntity me with | Success t -> match writeTaskToMQ t with | Success ts -> createResultMessage ts | Error -> Error | Error -> Error | Error -> Error | Error -> Error | Error -> Error

51

А как же композиция?

»

52

'a → Result<'b>

» 'b → Result<'c>

» 'c → Result<'d>

» …

Типы не совпадают...

53

Обработка ошибок#неработает

Нужно преобразование

('a → Result<'c>) → (Result<'a> → Result<'c>)

54

Обработка ошибок#решение

Обработка ошибок#решение

Нужно преобразование

('a → Result<'c>) → (Result<'a> → Result<'c>)

Как?

55

Обработка ошибок let handleRequest s = match readRequest s with | Success r -> match readEntityFromDB r with | Success e -> match modifyEntity e with | Success me -> match createTaskFromEntity me with | Success t -> match writeTaskToMQ t with | Success ts -> createResultMessage ts | Error -> Error | Error -> Error | Error -> Error | Error -> Error | Error -> Error

56

Обработка ошибок#паттернобнаружен

let handleRequest s = match readRequest s with | Success r -> match readEntityFromDB r with | Success e -> match modifyEntity e with | Success me -> match createTaskFromEntity me with | Success t -> match writeTaskToMQ t with | Success ts -> createResultMessage ts | Error -> Error | Error -> Error | Error -> Error | Error -> Error | Error -> Error

57

Обработка ошибок#связываем

let bind f = fun x -> match x with | Success r -> f r | Error -> x

('a → Result<'b>) → (Result<'a> → Result<'b>)

58

Обработка ошибок#композиция

let handleRequest = readRequest >> (bind readEntityFromDB) >> (bind modifyEntity) >> (bind createTaskFromEntity) >> (bind writeTaskToMQ) >> (bind createResultMessage)

59

Обработка ошибок#композиция

let handleRequest = readRequest >>= readEntityFromDB >>= modifyEntity >>= createTaskFromEntity >>= writeTaskToMQ >>= createResultMessage

60

Мы только что изобрели монаду

61

Сухой итог

● Функциональное программирование это просто● Можно использовать привычные приемы, но

проще● Можно заимствовать из функционального

программирования хитрые приемы● Монады совсем нестрашные

62

Спасибо за внимание

Акуляков АртёмСИБИНФОСОФТ

[email protected]/oxffaa