SlideShare ist ein Scribd-Unternehmen logo
1 von 73
Downloaden Sie, um offline zu lesen
Функциональное программирование
с использованием библиотеки fp-ts
Обо мне
● Программирую с 2014 года
● Активно применяю функциональный
подход на текущем проекте
Дмитрий Ховрич
Software Engineer в
Что такое функциональное
программирование?
Функциональное программирование
Функциональное программирование - это
программирование с использованием чистых
математических функций
Зачем писать код в функциональном стиле?
Функциональное программирование, как и любая другая парадигма,
накладывает дополнительные ограничения и правила.
Соблюдение этих ограничений и правил позволяет писать более надежный
код, который легче тестировать и повторно использовать.
Как мы можем себя ограничить во время написания кода?
“Хард” ограничения
● Компилятор TypeScript
○ Максимально строгий режим
○ TypeScript: Раскладываем tsconfig по
полочкам. Часть 1
○ TypeScript: Раскладываем tsconfig по
полочкам. Часть 2 — Всё про строгость
● ESLint
“Софт” ограничения
● Парадигма программирования
● Паттерны и лучшие практики
● Код ревью
Библиотека fp-ts
Библиотека fp-ts позволяет писать чистые функциональные приложения,
построенные поверх высокоуровневых абстракций из таких языков, как
Haskell, PureScript, и Scala.
● Паттерны и надежные абстракции из функционального мира
● Утилиты для композиции функций
● Функциональные типы данных
● Классы типов (type classes)
Класс типов
Класс типов определяет множество типизированных функций и констант,
которые должны существовать для каждого типа, который принадлежит
данному классу.
Основаны на теории категорий
Теория категорий
Теория категорий — раздел математики, изучающий свойства отношений
между математическими объектами, не зависящие от внутренней структуры
объектов.
Теперь еще математические теории учить?
Теория категорий
Вам не нужно изучать теорию
категорий для того, чтобы
использовать
функциональный подход в
Ваших программах!
Класс типов Show
interface Show<A> {
readonly show: (a: A) => string;
}
Тип A принадлежит классу Show, если для A определена функция show : (a:
A) => string
Реализации класса типов Show
const showNumber: Show<number> = {
show: n => n.toString()
};
const showUser: Show<User> = {
show: user => `User "${user.name}", ${user.age} years old`
};
Из чего состоит функциональное
программирование?
Из чего состоит функциональное программирование?
Концепции, которые
“лежат на поверхности”
Концепции, которые
“спрятаны поглубже”
Концепции, которые “лежат на поверхности”
● Иммутабельные данные
● Чистые функции (referentially transparent)
○ Каррирование
● Побочные эффекты
● “Честные” сигнатуры функций (method signature honesty)
● Композиция функций (бесточечный стиль)
Иммутабельные данные
● Изменение данных путем пересоздания объектов / массивов
● TypeScript не поддерживает иммутабельные типы данных в runtime
○ Но скоро могут появятся записи (records) и кортежи (tuples)
● Ключевое слово readonly
○ ReadonlyArray
○ ReadonlyRecord
○ ReadonlyMap
○ ReadonlySet
● eslint-plugin-functional
Иммутабельные данные
const arr: readonly number[] = [1, 2, 3];
arr.push(4); // Property 'push' does not exist on type 'readonly number[]'
arr.pop(); // Property 'pop' does not exist on type 'readonly number[]'.
arr.unshift(); // Property 'unshift' does not exist on type 'readonly number[]'.
arr.shift(); // Property 'shift' does not exist on type 'readonly number[]'
arr.splice(1); // Property 'splice' does not exist on type 'readonly number[]'
Чистые функции
const sum = (a: number, b: number): number => a + b;
const multiply = (a: number, b: number): number => a * b;
const subtract = (a: number, b: number): number => a - b;
const divide = (a: number, b: number): number => a / b;
const dateToString = (date: Date): string => date.toDateString();
Чистые каррированые функции
const sum = (a: number) => (b: number): number => a + b;
const multiply = (a: number) => (b: number): number => a * b;
const byEmail = (email: string) => (user: User): boolean =>
user.email === email;
// Удобно применять когда функция ожидает предикат на вход
const user = users.find(byEmail("peter-parker@gmail.com"));
Чистые функции могут мутировать данные внутри себя
function shuffle<T>(array: readonly T[]): readonly T[] {
const arrayCopy = [...array];
for (let i = arrayCopy.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = arrayCopy[i];
arrayCopy[i] = array[j];
arrayCopy[j] = temp;
}
return arrayCopy;
}
Побочные эффекты
Побочный эффект - это изменение состояния системы или наблюдаемое
взаимодействие с окружающим миром, происходящее во время вычисления
результата.
● изменения в файловой системе
● обращение к базе данных
● выполнение http-запроса
● выброс ошибок
● вывод на экран / запись в лог
● получение данных от пользователя
● выполнение запроса к DOM
Любое взаимодействие со средой вне функции является побочным эффектом.
Функции с побочными эффектами
const getCurrentDateIso = (): string => new Date().toISOString();
const log = <T>(key: string, value: T): void => console.log(`${key}: ${value}`);
const saveToStorage = <T>(key: string, value: T): void => {
localStorage.setItem(key, JSON.stringify(value));
};
const getFromStorage = (key: string): string | null => localStorage.getItem(key);
“Честные” сигнатуры функций
type User = {
readonly id: string;
readonly email: string;
};
declare function createUser(email: string): User;
Скрытые побочные эффекты внутри функции
function createUser(email: string): User {
if (email.length > 256) {
throw new Error("Email is too long!");
}
if (!email.includes("@")) {
throw new Error("Email is invalid!");
}
return { id: uuid(), email };
}
Композиция вызовов функций
Последовательные вызовы без композиции
const value = 2;
const valueAfterSum = sum(value, 2);
const valueAfterMultiply = multiply(valueAfterSum, 3);
const result = valueToString(valueAfterMultiply);
console.log(valueString); // 12
Неудобная композиция функций
const result =
valueToString(multiply(sum(value, 2), 3));
console.log(result); // 12
Композиция функций с применением pipe
import {pipe} from "fp-ts/function";
const value = 2;
const result = pipe(value, sum(2), multiply(3),
valueToString);
console.log(result); // 12
Как дебажить? Логами
const debug = <T>(key: string) => (value: T): T => {
console.log(`DEBUG:${key} : ${value}`);
return value;
}
Как дебажить? Логами
const result = pipe(
value,
sum(2),
debug("sum"), // DEBUG:sum : 4
multiply(3),
debug("multiply"), // DEBUG:multiply : 12
valueToString
);
console.log(result); // 12
Как дебажить? Логами
Используйте ESLint правило
no-restricted-imports для того, чтобы
“отловить” забытые debug функции
на этапе git commit или CI
А что может пойти не так?
declare function getUsers(): readonly User[];
declare function createFullName(user: User): string;
const users = getUsers();
const result = pipe(
users.find(byEmail("spider-man@gmail.com")),
createFullName
);
Проблема композиции функций. Код скомпилируется?
Проблема композиции функций
// Argument of type 'User | undefined' is not
assignable to parameter of type 'User'.
// Type 'undefined' is not assignable to type 'User'.
const result = pipe(
users.find(byEmail("spider-man@gmail.com")),
createFullName
);
Концепции, которые “спрятаны поглубже”
Объединения типов с дискриминантом
Объединения типов с дискриминантом
Объединения типов с дискриминантом - это объединения у которых
присутствует одно общее поле (с уникальным символом, чаще всего
строковым литералом).
Оно и будет служить дискриминантом, чтобы TypeScript по нему вывел что
же за тип у вас сейчас в руках.
Объединения типов с дискриминантом
type Success<T> = {
readonly type: "success";
readonly value: T;
}
type Fail = {
readonly type: "fail";
readonly error: Error;
}
type Result<T> = Success<T> | Fail;
Объединения типов с дискриминантом
declare function loadUsers(): Result<readonly User[]>;
const result = loadUsers();
// Property 'value' does not exist on type 'Result<readonly User[]>'
console.log(result.value);
// Property 'error' does not exist on type 'Result<readonly User[]>'
console.log(result.error);
Объединения типов с дискриминантом
switch (result.type) {
case "success":
console.log(result.value);
break;
case "fail":
console.log(result.error);
break;
default:
absurd(result); // typeof result is never
}
Тело функции absurd
function absurd<A>(_: never): A {
throw new Error('Called `absurd` function which
should be uncallable')
}
Option
Option
Option - конструкция, описывающая наличие или отсутствие значения.
С помощью функций map и chain позволяет работать с цепочками вызовов
функций даже если какая-то из них может вернуть null / undefined.
Option - тип данных, предоставляемый библиотекой fp-ts
● Описание типа
● Функции для взаимодействия
Описание типа Option
type None = {
readonly _tag: 'None';
};
type Some<A> = {
readonly _tag: 'Some';
readonly value: A;
};
type Option<A> = None | Some<A>;
Функции массивов, возвращающие Option
ReadonlyArray - head
declare const head:
<A>(as: readonly A[]) => Option<A>
ReadonlyArray - last
declare const last:
<A>(as: readonly A[]) => Option<A>
ReadonlyArray - lookup
declare const lookup:
(i: number) =>
<A>(as: ReadonlyArray<A>) =>
Option<A>
ReadonlyArray - findFirst
declare const findFirst:
<A>(predicate: Predicate<A>) =>
(as: ReadonlyArray<A>) =>
Option<A>
Predicate
interface Predicate<A> {
(a: A): boolean
}
Пример использование Option
import {findFirst} from "fp-ts/ReadonlyArray";
// Option<User>
// { _tag: 'Some', value: { id: 1, email: "spiderman@gmail.com" } }
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com"))
);
Пример использование Option
import { map } from "fp-ts/Option";
// Option<string>
// { _tag: 'Some', value: 'Peter Parker' }
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
map(createFullName)
);
Пример использование Option
import { map } from "fp-ts/Option";
// Option<string>
// { _tag: 'None' }
const value = pipe(
users,
findFirst(byEmail("mary-jane-watson@gmail.com")),
map(createFullName)
);
Описание типа функции Map для Option
type OptionMap =
<A, B>(f: (a: A) => B) =>
(fa: Option<A>) => Option<B>;
Реализация функции Map для Option
const map: OptionMap = f => option => {
switch (option._tag) {
case "None":
return option;
case "Some":
return { _tag: "Some", value: f(option.value) };
default:
return absurd(option)
}
}
map-ов может быть много
declare function stringHash(value: string): number;
// Option<number>
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
map(createFullName),
map(stringHash)
);
Функтор — это класс типов, для которых определена функция map и
соблюдаются некоторые законы:
● Закон идентичности
● Закон композиции
Законы - это ограничения, которые накладываются на реализацию функции
map.
В ежедневной работе Вам не придется писать свои функторы. Все
необходимые функторы реализованы в библиотеке fp-ts.
Функтор
Вложенные Option<T> - плохая практика
import {lookup} from "fp-ts/Record";
const comments: Record<UserId, readonly Comment[]> = {};
// Option<Option<readonly Comment[]>>
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
map(user => lookup(user.id, comments))
)
Record - lookup
declare const lookup:
<A>(k: string, r: Record<string, A>):
Option<A>
Как избавиться от вложенных Option<T>
import {chain} from "fp-ts/ReadonlyArray";
const comments: Record<UserId, readonly Comment[]> = {};
// Option<readonly Comment[]>
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
chain(user => lookup(user.id, comments))
)
Описание типа функции Chain для Option
type OptionChain =
<A, B>(f: (a: A) => Option<B>) =>
(fa: Option<A>) => Option<B>;
Реализация функции Chain для Option
const chain: OptionChain = f => option => {
switch (option._tag) {
case "None":
return option;
case "Some":
return f(option.value);
default:
return absurd(option)
}
}
Монада
Монада - это класс типов, для которой определены функции map, chain, of и
соблюдаются некоторые законы:
● Закон идентичности
● Закон ассоциативности
Законы - это ограничения, которые накладываются на реализацию функции
chain.
В ежедневной работе Вам не придется писать свои монады. Все
необходимые монады реализованы в библиотеке fp-ts.
Монады используются для последовательных вычислений.
Деструкторы
Как достать значение из Option?
import {toUndefined} from "fp-ts/Option";
// string | undefined
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
map(createFullName),
toUndefined
);
Как достать значение из Option?
import {constant} from "fp-ts/function";
import {getOrElse} from "fp-ts/Option";
// string
const value = pipe(
users,
findFirst(byEmail("spider-man@gmail.com")),
map(createFullName),
getOrElse(constant<string>("NO_NAME"))
);
Что еще интересного есть в fp-ts?
● Either - для работы с ошибками
● IO - для работы с побочными эффектами
● Task - для работы с асинхронным кодом
● TaskEither - для работы с асинхронным кодом, который может вернуть ошибку
● Reader - внедрение зависимостей в функциональном стиле
● State - для хранения состояния в композиции функций
● ReaderTaskEither - внедрение зависимостей в асинхронную функцию, которая
может вернуть ошибку
● Eq - для сравнения данных по значению
● Ord - для сортировки данных
● Semigroup - для конкатенации данных
● Monoid - для “сворачивания” данных (reduce)
Что почитать? Код из презентации
https://github.com/dkhovrich/fp-ts-talk-code#readme
Где пообщаться / попросить о помощи?
https://t.me/fp_ts
Вакансия в команду Spark
● продуктовая компания и возможность влиять на сам продукт
● команда профессионалов
● стек технологий (TypeScript, React, RxJS, fp-ts)
● пробуем новые инструменты, подходы
● достойный компенсационный пакет от компании
● гибридный гибкий график (офис, ремоут)
Все вакансии Readdle - https://readdle.com/careers 🚀
Контакты
Почта: khovrych.d@gmail.com
Дмитрий Ховрич
Software Engineer в
Спасибо!

Weitere ähnliche Inhalte

Was ist angesagt?

Introduction to AMQP Messaging with RabbitMQ
Introduction to AMQP Messaging with RabbitMQIntroduction to AMQP Messaging with RabbitMQ
Introduction to AMQP Messaging with RabbitMQDmitriy Samovskiy
 
SOA vs Microservices vs SBA
SOA vs Microservices vs SBASOA vs Microservices vs SBA
SOA vs Microservices vs SBAMichael Sukachev
 
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Chris Richardson
 
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022HostedbyConfluent
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass SlidesNir Kaufman
 
End to end Machine Learning using Kubeflow - Build, Train, Deploy and Manage
End to end Machine Learning using Kubeflow - Build, Train, Deploy and ManageEnd to end Machine Learning using Kubeflow - Build, Train, Deploy and Manage
End to end Machine Learning using Kubeflow - Build, Train, Deploy and ManageAnimesh Singh
 
How Apache Kafka® Works
How Apache Kafka® WorksHow Apache Kafka® Works
How Apache Kafka® Worksconfluent
 
Build Your Own CaaS (Container as a Service)
Build Your Own CaaS (Container as a Service)Build Your Own CaaS (Container as a Service)
Build Your Own CaaS (Container as a Service)HungWei Chiu
 
Angular - Chapter 4 - Data and Event Handling
 Angular - Chapter 4 - Data and Event Handling Angular - Chapter 4 - Data and Event Handling
Angular - Chapter 4 - Data and Event HandlingWebStackAcademy
 
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...confluent
 
State management in react applications (Statecharts)
State management in react applications (Statecharts)State management in react applications (Statecharts)
State management in react applications (Statecharts)Tomáš Drenčák
 
Health monitoring and dependency injection - CNUG November 2019
Health monitoring and dependency injection - CNUG November 2019Health monitoring and dependency injection - CNUG November 2019
Health monitoring and dependency injection - CNUG November 2019Alex Thissen
 
Introduction to Kubernetes Workshop
Introduction to Kubernetes WorkshopIntroduction to Kubernetes Workshop
Introduction to Kubernetes WorkshopBob Killen
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean ArchitectureBadoo
 

Was ist angesagt? (20)

Introduction to AMQP Messaging with RabbitMQ
Introduction to AMQP Messaging with RabbitMQIntroduction to AMQP Messaging with RabbitMQ
Introduction to AMQP Messaging with RabbitMQ
 
Understanding Monorepos
Understanding MonoreposUnderstanding Monorepos
Understanding Monorepos
 
SOA vs Microservices vs SBA
SOA vs Microservices vs SBASOA vs Microservices vs SBA
SOA vs Microservices vs SBA
 
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Unik Slides
Unik SlidesUnik Slides
Unik Slides
 
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
End to end Machine Learning using Kubeflow - Build, Train, Deploy and Manage
End to end Machine Learning using Kubeflow - Build, Train, Deploy and ManageEnd to end Machine Learning using Kubeflow - Build, Train, Deploy and Manage
End to end Machine Learning using Kubeflow - Build, Train, Deploy and Manage
 
How Apache Kafka® Works
How Apache Kafka® WorksHow Apache Kafka® Works
How Apache Kafka® Works
 
Containers 101
Containers 101Containers 101
Containers 101
 
Build Your Own CaaS (Container as a Service)
Build Your Own CaaS (Container as a Service)Build Your Own CaaS (Container as a Service)
Build Your Own CaaS (Container as a Service)
 
Angular - Chapter 4 - Data and Event Handling
 Angular - Chapter 4 - Data and Event Handling Angular - Chapter 4 - Data and Event Handling
Angular - Chapter 4 - Data and Event Handling
 
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...
Lessons Learned Building a Connector Using Kafka Connect (Katherine Stanley &...
 
State management in react applications (Statecharts)
State management in react applications (Statecharts)State management in react applications (Statecharts)
State management in react applications (Statecharts)
 
Clean Code
Clean CodeClean Code
Clean Code
 
TypeScript and Angular workshop
TypeScript and Angular workshopTypeScript and Angular workshop
TypeScript and Angular workshop
 
Health monitoring and dependency injection - CNUG November 2019
Health monitoring and dependency injection - CNUG November 2019Health monitoring and dependency injection - CNUG November 2019
Health monitoring and dependency injection - CNUG November 2019
 
Introduction to Kubernetes Workshop
Introduction to Kubernetes WorkshopIntroduction to Kubernetes Workshop
Introduction to Kubernetes Workshop
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 

Ähnlich wie Функциональное программирование с использованием библиотеки fp-ts | Odessa Frontend Meetup #19

C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.Igor Shkulipa
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 27bits
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
Иван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеИван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеYandex
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Stfalcon Meetups
 
C++ Базовый. Занятие 03.
C++ Базовый. Занятие 03.C++ Базовый. Занятие 03.
C++ Базовый. Занятие 03.Igor Shkulipa
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмыЕлена Ключева
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
 
особенности программирования на с++
особенности программирования на с++особенности программирования на с++
особенности программирования на с++mcroitor
 
javascript
javascriptjavascript
javascriptsovest
 
javascript_part1
javascript_part1javascript_part1
javascript_part1sovest
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программированияguestfc8ae0
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and ClojureVasil Remeniuk
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonovComputer Science Club
 

Ähnlich wie Функциональное программирование с использованием библиотеки fp-ts | Odessa Frontend Meetup #19 (20)

Step cpp022
Step cpp022Step cpp022
Step cpp022
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
Иван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеИван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программирование
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8
 
C++ Базовый. Занятие 03.
C++ Базовый. Занятие 03.C++ Базовый. Занятие 03.
C++ Базовый. Занятие 03.
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмы
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
 
особенности программирования на с++
особенности программирования на с++особенности программирования на с++
особенности программирования на с++
 
javascript
javascriptjavascript
javascript
 
javascript_part1
javascript_part1javascript_part1
javascript_part1
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программирования
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and Clojure
 
Урок 1. Что такое функциональное программирование
Урок 1. Что такое функциональное программированиеУрок 1. Что такое функциональное программирование
Урок 1. Что такое функциональное программирование
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 

Mehr von OdessaFrontend

Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19OdessaFrontend
 
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...OdessaFrontend
 
Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19OdessaFrontend
 
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18OdessaFrontend
 
Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17OdessaFrontend
 
Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17OdessaFrontend
 
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17OdessaFrontend
 
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17OdessaFrontend
 
Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16OdessaFrontend
 
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16OdessaFrontend
 
Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16OdessaFrontend
 
Современный станок верстальщика
Современный станок верстальщикаСовременный станок верстальщика
Современный станок верстальщикаOdessaFrontend
 
Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15OdessaFrontend
 
DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15OdessaFrontend
 
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15OdessaFrontend
 
Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15OdessaFrontend
 
Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14OdessaFrontend
 
Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13OdessaFrontend
 
Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13OdessaFrontend
 
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13OdessaFrontend
 

Mehr von OdessaFrontend (20)

Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19Викторина | Odessa Frontend Meetup #19
Викторина | Odessa Frontend Meetup #19
 
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
Использование Recoil в React и React Native приложениях | Odessa Frontend Mee...
 
Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19Великолепный Gatsby.js | Odessa Frontend Meetup #19
Великолепный Gatsby.js | Odessa Frontend Meetup #19
 
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
Canvas API как инструмент для работы с графикой | Odessa Frontend Meetup #18
 
Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17Викторина | Odessa Frontend Meetup #17
Викторина | Odessa Frontend Meetup #17
 
Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17Антихрупкий TypeScript | Odessa Frontend Meetup #17
Антихрупкий TypeScript | Odessa Frontend Meetup #17
 
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
Частые ошибки при разработке фронтенда | Odessa Frontend Meetup #17
 
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
OAuth2 и OpenID Connect простым языком | Odessa Frontend Meetup #17
 
Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16
 
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
Фриланс как профессиональная деградация | Odessa Frontend Meetup #16
 
Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16Cлайдер на CSS | Odessa Frontend Meetup #16
Cлайдер на CSS | Odessa Frontend Meetup #16
 
Современный станок верстальщика
Современный станок верстальщикаСовременный станок верстальщика
Современный станок верстальщика
 
Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15Викторина | Odessa Frontend Meetup #15
Викторина | Odessa Frontend Meetup #15
 
DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15DRY’им Vuex | Odessa Frontend Meetup #15
DRY’им Vuex | Odessa Frontend Meetup #15
 
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
А/Б тестирование: Что? Как? Зачем? | Odessa Frontend Meetup #15
 
Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15Пощупать 3д в браузере | Odessa Frontend Meetup #15
Пощупать 3д в браузере | Odessa Frontend Meetup #15
 
Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14Викторина | Odessa Frontend Meetup #14
Викторина | Odessa Frontend Meetup #14
 
Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13Викторина | Odessa Frontend Meetup #13
Викторина | Odessa Frontend Meetup #13
 
Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13Структуры данных в JavaScript | Odessa Frontend Meetup #13
Структуры данных в JavaScript | Odessa Frontend Meetup #13
 
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13
Эффективность с большой буквы Э… или любой другой | Odessa Frontend Meetup #13
 

Функциональное программирование с использованием библиотеки fp-ts | Odessa Frontend Meetup #19

  • 2. Обо мне ● Программирую с 2014 года ● Активно применяю функциональный подход на текущем проекте Дмитрий Ховрич Software Engineer в
  • 4. Функциональное программирование Функциональное программирование - это программирование с использованием чистых математических функций
  • 5. Зачем писать код в функциональном стиле? Функциональное программирование, как и любая другая парадигма, накладывает дополнительные ограничения и правила. Соблюдение этих ограничений и правил позволяет писать более надежный код, который легче тестировать и повторно использовать.
  • 6. Как мы можем себя ограничить во время написания кода? “Хард” ограничения ● Компилятор TypeScript ○ Максимально строгий режим ○ TypeScript: Раскладываем tsconfig по полочкам. Часть 1 ○ TypeScript: Раскладываем tsconfig по полочкам. Часть 2 — Всё про строгость ● ESLint “Софт” ограничения ● Парадигма программирования ● Паттерны и лучшие практики ● Код ревью
  • 7. Библиотека fp-ts Библиотека fp-ts позволяет писать чистые функциональные приложения, построенные поверх высокоуровневых абстракций из таких языков, как Haskell, PureScript, и Scala. ● Паттерны и надежные абстракции из функционального мира ● Утилиты для композиции функций ● Функциональные типы данных ● Классы типов (type classes)
  • 8. Класс типов Класс типов определяет множество типизированных функций и констант, которые должны существовать для каждого типа, который принадлежит данному классу. Основаны на теории категорий
  • 9. Теория категорий Теория категорий — раздел математики, изучающий свойства отношений между математическими объектами, не зависящие от внутренней структуры объектов.
  • 11. Теория категорий Вам не нужно изучать теорию категорий для того, чтобы использовать функциональный подход в Ваших программах!
  • 12. Класс типов Show interface Show<A> { readonly show: (a: A) => string; } Тип A принадлежит классу Show, если для A определена функция show : (a: A) => string
  • 13. Реализации класса типов Show const showNumber: Show<number> = { show: n => n.toString() }; const showUser: Show<User> = { show: user => `User "${user.name}", ${user.age} years old` };
  • 14. Из чего состоит функциональное программирование?
  • 15. Из чего состоит функциональное программирование? Концепции, которые “лежат на поверхности” Концепции, которые “спрятаны поглубже”
  • 16. Концепции, которые “лежат на поверхности” ● Иммутабельные данные ● Чистые функции (referentially transparent) ○ Каррирование ● Побочные эффекты ● “Честные” сигнатуры функций (method signature honesty) ● Композиция функций (бесточечный стиль)
  • 17. Иммутабельные данные ● Изменение данных путем пересоздания объектов / массивов ● TypeScript не поддерживает иммутабельные типы данных в runtime ○ Но скоро могут появятся записи (records) и кортежи (tuples) ● Ключевое слово readonly ○ ReadonlyArray ○ ReadonlyRecord ○ ReadonlyMap ○ ReadonlySet ● eslint-plugin-functional
  • 18. Иммутабельные данные const arr: readonly number[] = [1, 2, 3]; arr.push(4); // Property 'push' does not exist on type 'readonly number[]' arr.pop(); // Property 'pop' does not exist on type 'readonly number[]'. arr.unshift(); // Property 'unshift' does not exist on type 'readonly number[]'. arr.shift(); // Property 'shift' does not exist on type 'readonly number[]' arr.splice(1); // Property 'splice' does not exist on type 'readonly number[]'
  • 19. Чистые функции const sum = (a: number, b: number): number => a + b; const multiply = (a: number, b: number): number => a * b; const subtract = (a: number, b: number): number => a - b; const divide = (a: number, b: number): number => a / b; const dateToString = (date: Date): string => date.toDateString();
  • 20. Чистые каррированые функции const sum = (a: number) => (b: number): number => a + b; const multiply = (a: number) => (b: number): number => a * b; const byEmail = (email: string) => (user: User): boolean => user.email === email; // Удобно применять когда функция ожидает предикат на вход const user = users.find(byEmail("peter-parker@gmail.com"));
  • 21. Чистые функции могут мутировать данные внутри себя function shuffle<T>(array: readonly T[]): readonly T[] { const arrayCopy = [...array]; for (let i = arrayCopy.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); const temp = arrayCopy[i]; arrayCopy[i] = array[j]; arrayCopy[j] = temp; } return arrayCopy; }
  • 22. Побочные эффекты Побочный эффект - это изменение состояния системы или наблюдаемое взаимодействие с окружающим миром, происходящее во время вычисления результата. ● изменения в файловой системе ● обращение к базе данных ● выполнение http-запроса ● выброс ошибок ● вывод на экран / запись в лог ● получение данных от пользователя ● выполнение запроса к DOM Любое взаимодействие со средой вне функции является побочным эффектом.
  • 23. Функции с побочными эффектами const getCurrentDateIso = (): string => new Date().toISOString(); const log = <T>(key: string, value: T): void => console.log(`${key}: ${value}`); const saveToStorage = <T>(key: string, value: T): void => { localStorage.setItem(key, JSON.stringify(value)); }; const getFromStorage = (key: string): string | null => localStorage.getItem(key);
  • 24. “Честные” сигнатуры функций type User = { readonly id: string; readonly email: string; }; declare function createUser(email: string): User;
  • 25. Скрытые побочные эффекты внутри функции function createUser(email: string): User { if (email.length > 256) { throw new Error("Email is too long!"); } if (!email.includes("@")) { throw new Error("Email is invalid!"); } return { id: uuid(), email }; }
  • 27. Последовательные вызовы без композиции const value = 2; const valueAfterSum = sum(value, 2); const valueAfterMultiply = multiply(valueAfterSum, 3); const result = valueToString(valueAfterMultiply); console.log(valueString); // 12
  • 28. Неудобная композиция функций const result = valueToString(multiply(sum(value, 2), 3)); console.log(result); // 12
  • 29. Композиция функций с применением pipe import {pipe} from "fp-ts/function"; const value = 2; const result = pipe(value, sum(2), multiply(3), valueToString); console.log(result); // 12
  • 30. Как дебажить? Логами const debug = <T>(key: string) => (value: T): T => { console.log(`DEBUG:${key} : ${value}`); return value; }
  • 31. Как дебажить? Логами const result = pipe( value, sum(2), debug("sum"), // DEBUG:sum : 4 multiply(3), debug("multiply"), // DEBUG:multiply : 12 valueToString ); console.log(result); // 12
  • 32. Как дебажить? Логами Используйте ESLint правило no-restricted-imports для того, чтобы “отловить” забытые debug функции на этапе git commit или CI
  • 33. А что может пойти не так?
  • 34. declare function getUsers(): readonly User[]; declare function createFullName(user: User): string; const users = getUsers(); const result = pipe( users.find(byEmail("spider-man@gmail.com")), createFullName ); Проблема композиции функций. Код скомпилируется?
  • 35. Проблема композиции функций // Argument of type 'User | undefined' is not assignable to parameter of type 'User'. // Type 'undefined' is not assignable to type 'User'. const result = pipe( users.find(byEmail("spider-man@gmail.com")), createFullName );
  • 37. Объединения типов с дискриминантом
  • 38. Объединения типов с дискриминантом Объединения типов с дискриминантом - это объединения у которых присутствует одно общее поле (с уникальным символом, чаще всего строковым литералом). Оно и будет служить дискриминантом, чтобы TypeScript по нему вывел что же за тип у вас сейчас в руках.
  • 39. Объединения типов с дискриминантом type Success<T> = { readonly type: "success"; readonly value: T; } type Fail = { readonly type: "fail"; readonly error: Error; } type Result<T> = Success<T> | Fail;
  • 40. Объединения типов с дискриминантом declare function loadUsers(): Result<readonly User[]>; const result = loadUsers(); // Property 'value' does not exist on type 'Result<readonly User[]>' console.log(result.value); // Property 'error' does not exist on type 'Result<readonly User[]>' console.log(result.error);
  • 41. Объединения типов с дискриминантом switch (result.type) { case "success": console.log(result.value); break; case "fail": console.log(result.error); break; default: absurd(result); // typeof result is never }
  • 42. Тело функции absurd function absurd<A>(_: never): A { throw new Error('Called `absurd` function which should be uncallable') }
  • 44. Option Option - конструкция, описывающая наличие или отсутствие значения. С помощью функций map и chain позволяет работать с цепочками вызовов функций даже если какая-то из них может вернуть null / undefined. Option - тип данных, предоставляемый библиотекой fp-ts ● Описание типа ● Функции для взаимодействия
  • 45. Описание типа Option type None = { readonly _tag: 'None'; }; type Some<A> = { readonly _tag: 'Some'; readonly value: A; }; type Option<A> = None | Some<A>;
  • 47. ReadonlyArray - head declare const head: <A>(as: readonly A[]) => Option<A>
  • 48. ReadonlyArray - last declare const last: <A>(as: readonly A[]) => Option<A>
  • 49. ReadonlyArray - lookup declare const lookup: (i: number) => <A>(as: ReadonlyArray<A>) => Option<A>
  • 50. ReadonlyArray - findFirst declare const findFirst: <A>(predicate: Predicate<A>) => (as: ReadonlyArray<A>) => Option<A>
  • 52. Пример использование Option import {findFirst} from "fp-ts/ReadonlyArray"; // Option<User> // { _tag: 'Some', value: { id: 1, email: "spiderman@gmail.com" } } const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")) );
  • 53. Пример использование Option import { map } from "fp-ts/Option"; // Option<string> // { _tag: 'Some', value: 'Peter Parker' } const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), map(createFullName) );
  • 54. Пример использование Option import { map } from "fp-ts/Option"; // Option<string> // { _tag: 'None' } const value = pipe( users, findFirst(byEmail("mary-jane-watson@gmail.com")), map(createFullName) );
  • 55. Описание типа функции Map для Option type OptionMap = <A, B>(f: (a: A) => B) => (fa: Option<A>) => Option<B>;
  • 56. Реализация функции Map для Option const map: OptionMap = f => option => { switch (option._tag) { case "None": return option; case "Some": return { _tag: "Some", value: f(option.value) }; default: return absurd(option) } }
  • 57. map-ов может быть много declare function stringHash(value: string): number; // Option<number> const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), map(createFullName), map(stringHash) );
  • 58. Функтор — это класс типов, для которых определена функция map и соблюдаются некоторые законы: ● Закон идентичности ● Закон композиции Законы - это ограничения, которые накладываются на реализацию функции map. В ежедневной работе Вам не придется писать свои функторы. Все необходимые функторы реализованы в библиотеке fp-ts. Функтор
  • 59. Вложенные Option<T> - плохая практика import {lookup} from "fp-ts/Record"; const comments: Record<UserId, readonly Comment[]> = {}; // Option<Option<readonly Comment[]>> const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), map(user => lookup(user.id, comments)) )
  • 60. Record - lookup declare const lookup: <A>(k: string, r: Record<string, A>): Option<A>
  • 61. Как избавиться от вложенных Option<T> import {chain} from "fp-ts/ReadonlyArray"; const comments: Record<UserId, readonly Comment[]> = {}; // Option<readonly Comment[]> const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), chain(user => lookup(user.id, comments)) )
  • 62. Описание типа функции Chain для Option type OptionChain = <A, B>(f: (a: A) => Option<B>) => (fa: Option<A>) => Option<B>;
  • 63. Реализация функции Chain для Option const chain: OptionChain = f => option => { switch (option._tag) { case "None": return option; case "Some": return f(option.value); default: return absurd(option) } }
  • 64. Монада Монада - это класс типов, для которой определены функции map, chain, of и соблюдаются некоторые законы: ● Закон идентичности ● Закон ассоциативности Законы - это ограничения, которые накладываются на реализацию функции chain. В ежедневной работе Вам не придется писать свои монады. Все необходимые монады реализованы в библиотеке fp-ts. Монады используются для последовательных вычислений.
  • 66. Как достать значение из Option? import {toUndefined} from "fp-ts/Option"; // string | undefined const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), map(createFullName), toUndefined );
  • 67. Как достать значение из Option? import {constant} from "fp-ts/function"; import {getOrElse} from "fp-ts/Option"; // string const value = pipe( users, findFirst(byEmail("spider-man@gmail.com")), map(createFullName), getOrElse(constant<string>("NO_NAME")) );
  • 68. Что еще интересного есть в fp-ts? ● Either - для работы с ошибками ● IO - для работы с побочными эффектами ● Task - для работы с асинхронным кодом ● TaskEither - для работы с асинхронным кодом, который может вернуть ошибку ● Reader - внедрение зависимостей в функциональном стиле ● State - для хранения состояния в композиции функций ● ReaderTaskEither - внедрение зависимостей в асинхронную функцию, которая может вернуть ошибку ● Eq - для сравнения данных по значению ● Ord - для сортировки данных ● Semigroup - для конкатенации данных ● Monoid - для “сворачивания” данных (reduce)
  • 69. Что почитать? Код из презентации https://github.com/dkhovrich/fp-ts-talk-code#readme
  • 70. Где пообщаться / попросить о помощи? https://t.me/fp_ts
  • 71. Вакансия в команду Spark ● продуктовая компания и возможность влиять на сам продукт ● команда профессионалов ● стек технологий (TypeScript, React, RxJS, fp-ts) ● пробуем новые инструменты, подходы ● достойный компенсационный пакет от компании ● гибридный гибкий график (офис, ремоут) Все вакансии Readdle - https://readdle.com/careers 🚀