Функциональное Программирование в C#. Продолжение
Начало
Продолжение
3. Монадическое связывание
Монада — это контейнер для значений, например List<T>, IEnumerable<T> или Task<T>. Особенностью её является то, что вы можете объединять операции с содержащимися значениями, не имея дела с контейнером напрямую. Такое объединение называется монадическим связыванием. Вы ежедневно используете монадическое связывание в LINQ, не осознавая этого. Оно позволяет объединять операции, преобразующие данные.
Select преобразует значения:
var numbers = new[] { 1, 2, 3, 4 };
var doubled = numbers.Select(x => x * 2);Операции, возвращающие множество значений, используют SelectMany:
var folders = new[] { "docs", "photos" };
var files = folders.SelectMany(
f => Directory.GetFiles(f));Популярным примером применения монад на практике является шаблон Result, который обеспечивает простой способ объединения операций, которые могут завершиться неудачей.
4. Чистые функции
Чистые функции предсказуемы: они зависят только от своих входных данных и ничего не меняют в системе. Никаких вызовов базы данных, никаких запросов API, никакого глобального состояния. Это ограничение упрощает их понимание, тестирование и отладку.
Не чистая функция – использует общее состояние:
public class PriceCalculator
{
private decimal _tax;
private List<Discount> _discounts;
public decimal CalculatePrice(Order order)
{
var price = order.Items.Sum(i => i.Price);
foreach (var d in _discounts)
price -= d.Calculate(price);
return price * (1 + _tax);
}
}
А вот пример чистой функции:
public static class PriceCalculator
{
public static decimal CalculatePrice(
Order order,
decimal tax,
IReadOnlyList<Discount> discounts)
{
var price = order.Items.Sum(i => i.Price);
var discounted = discounts.Aggregate(
price,
(pr, disc) => pr - disc.Calculate(pr));
return discounted * (1 + tax);
}
}
Чистые функции потокобезопасны, просты в тестировании и просты в обосновании, поскольку все зависимости явные.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/functional-programming-in-csharp-the-practical-parts