Вадлер, Филип , 2001 Прочтите этот пост на испанском языке
Монады – одна из многих концепций, разделяемых математикой и функциональным программированием. Он исходит из теории категорий для решения таких проблем, как контроль исключений, счетчики или трассировки выполнения. Эти проблемы легко решить на императивных языках, но на чистых языках это может быть немного сложнее.
Чисто функциональные языки обладают этим преимуществом: весь поток данных делается явным. И этот недостаток: иногда он бывает болезненно явным.
В документе объясняется, как этот явный поток данных улучшает модульность и важность этой функции в программировании.
В документе объясняется, как этот явный поток данных улучшает модульность и важность этой функции в программировании.
Монада, также называемая стандартной конструкцией, представляет собой структуру данных, которая инкапсулирует поведение. Такое поведение обычно реализуется как побочные эффекты в императивном программировании. Ключевым примером для понимания монад является истинное значение в Scala или VAVR (функциональные структуры данных для JAVA), которые инкапсулируют исключения. Это значение можно использовать для составления функций без явного управления каждой возможной ошибкой до окончательного применения.
public static Trydivide(Integer dividend, Integer divider) { return Try.of(() -> dividend/divider); } public static void main(String[] args) { Try result = divide(100, 0).flatMap(r1 -> divide(r1, 10)); System.out.println("RESULT 1 = " + resultado.map(String::valueOf) .getOrElseGet(Throwable::getMessage)); // RESULT 1 = / by zero result = divide(100, 10).flatMap(r1 -> divide(r1, 10)); System.out.println("RESULT 2 = " + resultado.map(String::valueOf) .getOrElseGet(Throwable::getMessage)); // RESULT 2 = 1 }
Законы Монад
Формальное определение монады включает 3 закона, определяющих, является ли структура монадой. Эти законы, возможно, имеют больше теоретической, чем практической ценности, но этот блог посвящен статье: P поэтому я попытаюсь объяснить принципы.
Левая единица измерения/Левая идентичность
Этот закон гласит, что применение функции к значению и применение ее к монаде с одинаковым значением внутри должно быть одинаковым, если вы используете правильную композицию (карту или плоскую карту в соответствии с возвращением функции).
public static void main(String[] args) { Integer hundred = 100; TrytryHundred = Try.of(() -> hundred); Boolean r = tryHundred.flatMap(value -> divide(100, value)) .equals(divide(100, hundred)); // True }
return a >>= f = f
Правильное подразделение/Правильная идентичность
Как и в предыдущем законе, если у нас есть функция, которая получает значение и инкапсулирует результат в монаде, результат применения ее к значению или объединения ее с другой функцией монады должен быть одинаковым.
public static void main(String[] args) { Integer hundred = 100; TrytryHundred = Try.of(() -> hundred); // success return the same value encapsulated in a Try but cannot catch exceptions Boolean r = tryHundred.flatMap(value -> Try.success(value)) .equals(Try.success(hundred));// True }
m >>= return = m
Эти примеры в JAVA, по-видимому, имеют одинаковую реализацию, но разница между обоими законами более очевидна в Haskell. Как я уже сказал, эти законы – риторика, а Хаскелл чисто функционален и более близок к математике.
Ассоциативность
Закон ассоциативности гласит, что мы должны иметь возможность составлять функции последовательно или вызывать одну в качестве входных данных другой.
public class MonadTest { public static TrydivideByTen(Integer dividend) { return Try.of(() -> dividend/10); } public static Try doubleVal(Integer n1) { return Try.of(() -> n1 * 2); } public static void main(String[] args) { Try tryHundred = Try.of(() -> 100); Try r1 = tryHundred.flatMap(MonadTest::divideByTen).flatMap(doubleVal::doubleVal); Try r2 = tryHundred.flatMap( hundred -> divideByTen(hundred).flatMap(MonadTest::doubleVal) ); Boolean r = r1.equals(r2);// True } }
(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
Оригинал: “https://dev.to/gustavo94/digest-of-papers–monads-for-functional-programming-47fp”