Что такое монада в программировании
Перейти к содержимому

Что такое монада в программировании

  • автор:

Монада (программирование)

Мона́да в программировании — это абстракция линейной цепочки связанных вычислений. Её основное назначение — инкапсуляция функций с побочным эффектом от чистых функций, а точнее их выполнений от вычислений [1] . Монады применяются в языке Haskell, так как он повсеместно использует ленивые вычисления, которые вместе с побочным эффектом, как правило, образуют плохо прогнозируемый результат. Она описывается [2] полиморфным контейнерным типом для выполнений с одним параметром, стратегией «поднятия» значения в монаду и стратегией связывания двух вычислений, второе из которых зависит от параметра, вычисляемого первым:

m :: * -> * class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a class Functor f where fmap :: (a -> b) -> f a -> f b

Функция return описывает «возвращение» (втягивание) типа a в монаду m , то есть обрамление его контейнером. Функция fail не имеет отношения к теоретической сущности монад, однако используется в случае ошибки сопоставления с образцом внутри монадического кода — останавливает процесс последовательных действий и выводит сообщение о причине ошибки (в будущих версиях библиотеки может быть переведён в отдельный класс [3] ). Оператор >>= описывает, что в монаде действия происходят последовательно, то есть после применения функции её результат передаётся далее (.. -> a -> b -> ..), примером которой может быть передача текста в буфер: типы данные облачаются в монаду (конструктором), а затем с ними функция производит действия, в данном случае добавление. Оператор >> — частный случай оператора >>= , когда предыдущие данные просто заменяются следующими, которые не формируются на основании предыдущих.

В частности, к монадам относятся:

  • IO (монада строго последовательных вычислений): стратегия связывания — «сначала первое вычисление, затем второе»;
  • Maybe (монада вычислений с отсутствующими значениями): стратегия связывания — «если первое вычисление дало результат, то второе; иначе — отсутствие результата»;
  • List (монада вычислений с несколькими результатами): стратегия связывания — «все возможные результаты второго вычисления, примененного к каждому из вычисленных первым значений параметра»;
  • State (монада вычислений с переменной состояния): стратегия связывания — «начать второе вычисление с состоянием, измененным в результате первого»;
  • и некоторые другие типы.

Монады также применяются для синтаксического анализа, продолжений (continuations), вероятностных вычислений и в других случаях.

Концепция монад в программировании была унаследована из теории категорий: Монада (математика)

Примечания

  1. Контейнер не имеет задачи инкапсулирования данных.
  2. Описание класса Monad находится в модуле Monad пакета Control и в стандартном модуле Prelude , класса Functor и MonadPlus — только в модуле Monad пакета Control .
  3. Евгений Кирпичев.Монады в Haskell (рус.) . Монады — «обобщение некоторых привычных идиом, а также как еще один метод для их абстракции».

Ссылки

Учебные пособия

  • Monad Tutorials Timeline (англ.) Большая коллекция пособий по монадам, представлены в порядке появления.
  • What the hell are Monads?
  • You Could Have Invented Monads! (And Maybe You Already Have.), простое введение
  • All About Monads
  • Monads as Computation
  • Monads as Containers
  • Monads for the Working Haskell Programmer
  • The Haskell Programmer’s Guide to the IO Monad — Don’t Panic
  • Introduction to Haskell, Part 3: Monads
  • On Monads
  • Crash Monad Tutorial (англ.) — статья о монадах, объясняющая их с точки зрения теории категорий
  • Learn You a Haskell for Great Good! (англ.) — книга содержит доступное описание языка Haskell, в котором много внимания уделено понятию монады и аналогичным конструкциям

Другие статьи

  • A tour of the Haskell Monad functions (англ.)
  • Notions of Computation and Monads от Eugenio Moggi, первая статья, предлагающая использование монад в программировании
  • «Monads for Functional Programming» от Philip Wadler, описание монад в языке Хаскелл (написано еще до того, как они в нем появились)
  • 4. Монады — простое изложение основ языка

Литература

  • Душкин Р.В. Охрана // Приёмы программирования // Функции // Синтаксис и идиомы языка // Справочник по языку Haskell / Гл. ред. Д. А. Мовчан. — М .: ДМК Пресс, 2008. — С. 37-38. — 554 с. — 1500 экз. — ISBN 5-94074-410-9, ББК 32.973.26-018.2, УДК 004.4
  • П. Д. Симон. 8. Лекция: Стандартное начало (Prelude) // Язык и библиотеки Haskell 98.
  • Erkok Levent. Value Recursion in Monadic Computations. Oregon Graduate Institute. — 2002. — 162 p.
  • Теория категорий
  • Haskell
  • Концепции языков программирования

Wikimedia Foundation . 2010 .

Монада (программирование)

Мона́да — особый тип данных в функциональных языках программирования, для которого возможно задать императивную последовательность выполнения некоторых операций над хранимыми значениями [1] . Монады позволяют задавать последовательность выполнения операций, производить операции с побочными эффектами и другие действия, которые сложно или вовсе невозможно реализовать в функциональной парадигме программирования другими способами.

Концепция монады и термин изначально происходят из теории категорий, где она определяется как функтор с дополнительной структурой. Исследования, начатые в конце 1980-х — начале 1990-х годов, установили, что монады могут привнести, казалось бы, разрозненные проблемы компьютерной науки в единую функциональную модель. Теория категорий также выдвигает несколько формальных требований [каких?] , так называемых монадических законов, которые должны соблюдаться любой монадой и могут быть использованы для верификации монадического кода.

Описание [ править | править код ]

Монады чаще всего используются в функциональных языках программирования. При ленивой модели вычисления порядок редукции неизвестен. Например, вычисление 1 + 3 + 6 может быть редуцировано в 1 + 9 или 4 + 6 . Монады позволяют упорядочить редукцию. Поэтому существует ироничное утверждение, что монады — это способ перегрузить оператор «точка с запятой».

Монада является контейнером, который хранит в себе значение произвольного типа. Она должна обладать функцией связывания (bind), которая принимает два аргумента: текущее значение монады и функцию, принимающую значение типа, который содержит текущая монада и возвращающая новую монаду. Результатом вызова функции связывания будет новая монада, полученная путём применения первого аргумента ко второму. Так могла бы выглядеть монада в императивном языке Java и одна из её реализаций, контейнер Maybe:

import java.util.function.Function; interface MonadT>  U> MonadU> bind(FunctionT, MonadU>> f); > class MaybeT> implements MonadT>  private final T val; public Maybe(T val)  this.val = val; > public T getVal()  return val; > @Override public U> MonadU> bind(FunctionT, MonadU>> f)  if (val == null) return new MaybeU>(null); return f.apply(val); > > public class MonadApp  public static void main(String[] args)  MaybeInteger> x = new Maybe<>(5); MonadInteger> y = x .bind(v -> new Maybe<>(v + 1)) .bind(v -> new Maybe<>(v * 2)); System.out.println( ((MaybeInteger>)y).getVal() ); > > 

Появившиеся в Java 8 функциональные интерфейсы позволяют реализовать интерфейс, похожий на монаду.

В Haskell [ править | править код ]

Класс Monad присутствует в стандартном модуле Prelude . Для реализации данного класса требуется любой однопараметрический тип (тип рода * -> * ). Монада обладает четырьмя методами

class Functor f where fmap :: (a -> b) -> f a -> f b class Functor f => Applicative f where pure :: a -> f a ( ) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b () :: f a -> f b -> f a -- m :: * -> * class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b -- реализован по-умолчанию: a >> b = a >>= \_ -> b return :: a -> m a -- = pure fail :: String -> m a -- по-умолчанию вызывает errorWithoutStackTrace 

Метод return может ввести в заблуждение программистов, знакомых с императивными языками: он не прерывает вычисления, а лишь упаковывает произвольное значение типа a в монаду m . Метод fail не имеет отношения к теоретической сущности монад, однако используется в случае ошибки сопоставления с образцом внутри монадического вычисления. [2] ). Оператор >>= является функцией связывания. Оператор >> — частный случай оператора >>= , используется когда нам не важен результат связывания.

Некоторые типы, реализующие класс Monad:

  • IO , используется для функций с побочным эффектом. Конструкторы IO скрыты от программиста, также отсутствуют функции распаковки монады. Это не позволяет вызывать грязные функции из чистых.
  • Maybe . Вычисление прерывается, если получено значение Nothing.
  • [] (список) . Вычисление прерывается при пустом списке. При непустом списке оператор >>= вызывает функцию для каждого элемента списка.
  • Reader .
  • Writer .
  • State . Помимо возможностей Reader позволяет изменять состояние.

В языке также присутствует do -нотация, которая является более удобной формой записи монадических функций. В данном примере f1 использует do -нотацию, а f2 записана с помощью операторов связывания:

f1 = do s  getLine putStrLn $ "Hello " ++ s putStrLn "Goodbye" f2 = getLine >>= (\s -> putStrLn $ "Hello " ++ s) >> putStrLn "Goodbye" 

Примечания [ править | править код ]

  1. ↑Душкин-ФП, 2008, с. 215.
  2. Евгений Кирпичев.Монады в Haskell(рус.) . Архивировано 16 января 2017 года. Монады — «обобщение некоторых привычных идиом, а также как ещё один метод для их абстракции».

Ссылки [ править | править код ]

Учебные пособия [ править | править код ]

  • Monad Tutorials Timeline(англ.) Большая коллекция пособий по монадам, представлены в порядке появления.
  • What the hell are Monads?
  • You Could Have Invented Monads! (And Maybe You Already Have.), простое введение
  • Monads as Computation
  • Monads as Containers
  • Monads for the Working Haskell Programmer
  • The Haskell Programmer’s Guide to the IO Monad — Don’t Panic
  • Introduction to Haskell, Part 3: Monads
  • On Monads
  • Crash Monad Tutorial(англ.) — статья о монадах, объясняющая их с точки зрения теории категорий
  • Learn You a Haskell for Great Good!(англ.) — книга содержит доступное описание языка Haskell, в котором много внимания уделено понятию монады и аналогичным конструкциям

Другие статьи [ править | править код ]

  • A tour of the Haskell Monad functions(англ.)
  • Notions of Computation and Monads от Eugenio Moggi, первая статья, предлагающая использование монад в программировании
  • «Monads for Functional Programming» от Philip Wadler, описание монад в языке Хаскелл (написано ещё до того, как они в нём появились)
  • 4. Монады — простое изложение основ языка

Литература [ править | править код ]

  • Душкин Р.В. Охрана // Приёмы программирования // Функции // Синтаксис и идиомы языка // Справочник по языку Haskell / Гл. ред. Д. А. Мовчан. — М. : ДМК Пресс, 2008. — С. 37—38. — 554 с. — 1500 экз. — ISBN 5-94074-410-9, ББК 32.973.26-018.2, УДК 004.4.
  • Душкин Р. В. Функциональное программирование на языке Haskell. — М. : ДМК Пресс, 2008. — 609 с. — ISBN 5-94074-335-8.
  • Пейтон-Джонс, Саймон. 8. Лекция: Стандартное начало (Prelude) // Язык и библиотеки Haskell 98.
  • Erkok Levent. Value Recursion in Monadic Computations. Oregon Graduate Institute. — 2002. — 162 p.
  • Теория категорий
  • Haskell
  • Концепции языков программирования
  • Страницы, использующие устаревший тег source
  • Википедия:Статьи, требующие конкретизации
  • Википедия:Статьи с шаблонами недостатков по алфавиту
  • Страницы, использующие волшебные ссылки ISBN

Монады за 15 минут

На конференции YOW! 2013 один из разработчиков языка Haskell, проф. Филип Вадлер, показал, как монады позволяют чистым функциональным языкам осуществлять императивные по сути операции, такие, как ввод-вывод и обработку исключений. Неудивительно, что интерес аудитории к этой теме породил взрывной рост публикаций о монадах в Интернет. К сожалению, бо́льшая часть этих публикаций использует примеры, написанные на функциональных языках, подразумевая, что о монадах хотят узнать новички в функциональном программировании. Но монады не специфичны для Haskell или функциональных языков, и вполне могут быть проиллюстрированы примерами на императивных языках программирования. Это и является целью данного руководства.

Чем это руководство отличается от остальных? Мы попытаемся не более чем за 15 минут «открыть» монады, используя лишь интуицию и несколько элементарных примеров кода на Python. Мы поэтому не станем теоретизировать и углубляться в философию, рассуждая о буррито, космических скафандрах, письменных столах и эндофункторах.

Мотивационные примеры

Мы рассмотрим три проблемы, относящиеся к композиции функций. Мы решим их двумя способами: обычным императивным и при помощи монад. Затем мы сравним разные подходы.

1. Логгирование

Допустим, у нас есть три унарные функции: f1 , f2 и f3 , принимающие число и возвращающие его увеличенным на 1, 2 и 3 соответственно. Также каждая функция генерирует сообщение, представляющее собой отчёт о выполненной операции.

def f1(x): return (x + 1, str(x) + "+1") def f2(x): return (x + 2, str(x) + "+2") def f3(x): return (x + 3, str(x) + "+3")

Мы хотели бы объединить их в цепочку для обработки параметра x , иначе говоря, мы хотели бы вычислить x+1+2+3 . Кроме того, нам нужно получить человекочитаемое объяснение того, что было сделано каждой функцией.

Можно добиться нужного нам результата следующим способом:

log = "Ops:" res, log1 = f1(x) log += log1 + ";" res, log2 = f2(res) log += log2 + ";" res, log3 = f3(res) log += log3 + ";" print(res, log)

Это решение неидеально, так как состоит из большого количества однообразного связующего кода. Если мы захотим добавить к нашей цепочке новую функцию, мы вынуждены будем повторить этот связующий код. Кроме того, манипуляции с переменными res и log ухудшают читаемость кода, мешая следить за основной логикой программы.

В идеале, программа должна выглядеть как простая цепочка функций, вроде f3(f2(f1(x))) . К сожалению, типы данных, возвращаемых f1 и f2 , не соответствуют типам параметров f2 и f3 . Но мы можем добавить в цепочку новые функции:

def unit(x): return (x, "Ops:") def bind(t, f): res = f(t[0]) return (res[0], t[1] + res[1] + ";")

Теперь мы можем решить проблему следующим образом:

print(bind(bind(bind(unit(x), f1), f2), f3))

Следующая диаграмма показывает вычислительный процесс, происходящий при x=0 . Здесь v1 , v2 и v3 − значения, полученные в результате вызовов unit и bind .

Функция unit преобразует входной параметр x в кортеж из числа и строки. Функция bind вызывает функцию, переданную ей в качестве параметра, и накапливает результат в промежуточной переменной t .

Мы смогли избежать повторений связующего кода, поместив его в функцию bind . Теперь, если у нас появится функция f4 , мы просто включим её в цепочку:

bind(f4, bind(f3, . ))

И никаких других изменений нам делать не понадобится.

2. Список промежуточных значений

Этот пример мы также начнём с простых унарных функций.

def f1(x): return x + 1 def f2(x): return x + 2 def f3(x): return x + 3

Как и в предыдущем примере, нам нужно скомпоновать эти функции, чтобы вычислить x+1+2+3 . Также нам нужно получить список всех значений, полученных в результате работы наших функций, то есть x , x+1 , x+1+2 и x+1+2+3 .

В отличие от предыдущего примера, наши функции компонуемы, то есть типы их входных параметров совпадают с типом результата. Поэтому простая цепочка f3(f2(f1(x))) вернёт нам конечный результат. Но в таком случае мы потеряем промежуточные значения.

Решим задачу «в лоб»:

lst = [x] res = f1(x) lst.append(res) res = f2(res) lst.append(res) res = f3(res) lst.append(res) print(res, lst)

К сожалению, это решение также содержит много связующего кода. И если мы решим добавить f4 , нам опять придётся повторять этот код, чтобы получить верный список промежуточных значений.

Поэтому добавим две дополнительные функции, как и в предыдущем примере:

def unit(x): return (x, [x]) def bind(t, f): res = f(t[0]) return (res, t[1] + [res])

Теперь мы перепишем программу в виде цепочки вызовов:

print(bind(bind(bind(unit(x), f1), f2), f3))

Следующая диаграмма показывает вычислительный процесс, происходящий при x=0 . Снова v1 , v2 и v3 обозначают значения, полученные в результате вызовов unit и bind .

3. Пустые значения

Попробуем привести более интересный пример, на этот раз с классами и объектами. Допустим, у нас есть класс Employee с двумя методами:

class Employee: def get_boss(self): # Return the employee's boss def get_wage(self): # Compute the wage

Каждый объект класса Employee имеет руководителя (другой объект класса Employee ) и зарплату, доступ к которым осуществляется через соответствующие методы. Оба метода могут также возвращать None (работник не имеет руководителя, зарплата неизвестна).

В этом примере мы создадим программу, которая показывает зарплату руководителя данного работника. Если руководитель не найден, или его зарплата не может быть определена, то программа вернёт None .

В идеале нам нужно написать что-то вроде

print(john.get_boss().get_wage())

Но в таком случае, если какой-то из методов вернёт None , наша программа завершится с ошибкой.

Очевидный способ учесть эту ситуацию может выглядеть так:

result = None if john is not None and john.get_boss() is not None and john.get_boss().get_wage() is not None: result = john.get_boss().get_wage() print(result)

В этом случае мы допускаем лишние вызовы методов get_boss и get_wage . Если эти методы достаточно тяжелы (например, обращаются к базе данных), наше решение не годится. Поэтому изменим его:

result = None if john is not None: boss = john.get_boss() if boss is not None: wage = boss.get_wage() if wage is not None: result = wage print(result)

Этот код оптимален в плане вычислений, но плохо читается за счёт трёх вложенных if . Поэтому попробуем использовать тот же трюк, что и в предыдущих примерах. Определим две функции:

def unit(e): return e def bind(e, f): return None if e is None else f(e)

И теперь мы можем скомпоновать всё решение в одну строку.

print(bind(bind(unit(john), Employee.get_boss), Employee.get_wage))

Как вы, наверное, уже заметили, в этом случае нам не обязательно было писать функцию unit : она просто возвращает входной параметр. Но мы оставим её, чтобы нам легче было потом обобщить наш опыт.

Обратите внимание также на то, что в Python мы можем использовать методы как функции, что позволило нам написать Employee.get_boss(john) вместо john.get_boss() .

Следующая диаграмма показывает процесс вычислений в том случае, когда у Джона нет руководителя, то есть john.get_boss() возвращает None .

Выводы

Допустим, мы хотим объединить однотипные функции f1 , f2 , … , fn . Если их входные параметры совпадают по типу с результатами, мы можем использовать простую цепочку вида fn(… f2(f1(x)) …) . Следующая диаграмма показывает обобщённый процесс вычислений с промежуточными результатами, обозначенными как v1 , v2 , … , vn .

Зачастую этот подход неприменим. Типы входных значений и результатов функций могут различаться, как в первом примере. Либо же функции могут быть компонуемы, но мы хотим вставить дополнительную логику между вызовами, как в примерах 2 и 3 мы вставляли аггрегацию промежуточных значений и проверку на пустое значение соответственно.

1. Императивное решение

Во всех примерах мы вначале использовали самый прямолинейный подход, который можно отобразить следующей диаграммой:

Перед вызовом f1 мы выполняли некоторую инициализацию. В первом примере мы инициализировали переменную для хранения общего лога, во втором − для списка промежуточных значений. После этого мы перемежали вызовы функций неким связующим кодом: вычисляли агрегатные значения, проверяли результат на None .

2. Монады

Как мы видели на примерах, императивные решения всегда страдали многословностью, повторениями и запутанной логикой. Чтобы получить более элегантный код, мы использовали некий шаблон проектирования, согласно которому мы создавали две функции: unit и bind . Этот шаблон и называется монадой. Функция bind содержит связующий код, в то время, как unit осуществляет инициализацию. Это позволяет упростить итоговое решение до одной строки:

bind(bind( . bind(bind(unit(x), f1), f2) . fn-1), fn)

Процесс вычисления можно представить диаграммой:

Вызов unit(x) генерирует начальное значение v1 . Затем bind(v1, f1) генерирует новое промежуточное значение v2 , которое используется в следующем вызове bind(v2, f2) . Этот процесс продолжается, пока не будет получен итоговый результат. Определяя различные unit и bind в рамках этого шаблона, мы можем объединять различные функции в одну цепочку вычислений. Библиотеки монад (например, PyMonad или OSlash, − прим. перев.) обычно содержат готовые к употреблению монады (пары функций unit и bind ) для реализации определённых композиций функций.

Чтобы собрать функции в цепочку, значения, возвращаемые unit и bind , должны быть того же типа, что и входные параметры bind . Этот тип называется монадическим. В терминах вышеприведённой диаграммы, тип переменных v1 , v2 , … , vn должен быть монадическим типом.

Наконец, рассмотрим, как можно улучшить код, написанный с использованием монад. Очевидно, повторяющиеся вызовы bind выглядят неэлегантно. Чтобы избежать этого, определим ещё одну внешнюю функцию:

def pipeline(e, *functions): for f in functions: e = bind(e, f) return e

Теперь вместо

bind(bind(bind(bind(unit(x), f1), f2), f3), f4)

мы можем использовать следующее сокращение:

pipeline(unit(x), f1, f2, f3, f4)

Заключение

Монады − это простой и мощный шаблон проектирования, используемый для композиции функций. В декларативных языках программирования он помогает реализовать такие императивные механизмы, как логгирование или ввод/вывод. В императивных языках
он помогает обобщить и сократить код, связывающий серию вызовов однотипных функций.

Эта статья даёт только поверхностное, интуитивное понимание монад. Вы можете узнать больше, обратившись к следующим источникам:

  1. Википедия
  2. Monads in Python (with nice syntax!)
  3. Monad tutorials timeline
  • Python
  • Функциональное программирование

Javascript и монада Maybe

Javascript и монада Maybe

В какой-то момент мне надоело писать что-то типа object && object.prop1 && object.prop1.prop2 . Это ужасно и неправильно. Кроме очевидного варианта с перехватом исключения try/catch, нашлись опциональные цепочки, и, конечно же, монады.

В новых версиях JS появились опциональные цепочки ?. , безопасный способ доступа к свойствам вложенных объектов, даже если какое-либо из промежуточных свойств не существует, то есть вместо user && user.address && user.address.street можно написать user?.address?.street . Но в моем случае этот вариант не подошел, использовалась старая версия Node.js.

Во-первых, а что такое монада? Монада — это особый тип данных в функциональных языках программирования. Про функциональное программирование я только слышал и считал, что это не про Javascript, а оказалось, что даже на вики написано:

Поддерживает объектно-ориентированный, императивный и функциональный стили.

Вот про функциональный стиль Javascript мы сегодня и поговорим. Я не буду углубляться в определение что такое монада и цитировать умные книжки, а расскажу как я понял её сам. Монада — это что-то вроде контейнера, который поддерживает определенные стандартами операции. Самый первый стандарт, который находит Google — это Fantasy Land.

В общем и целом, монада должна поддерживать как минимум:

Это позволяет соединять различные (или даже одинаковые) монады в цепочки, так как все они следуют единому стандарту.

Есть куча готовых библиотек с различными готовыми монадами, но это не наш метод, чтобы разобраться как это работает — нужно написать свою версию монады Maybe. Ниже одна из реализаций класса Maybe, уверен, что не полная, а может быть и где-то неправильная, но моя.

class Maybe < constructor(val) < this.__value = val; >static of(val) < return new Maybe(val); >static Nothing() < return Maybe.of(null); >flatMap(fn) < if(this.isNothing()) return Maybe.Nothing(); const m = fn(this.__value); return m.isNothing() ? Maybe.Nothing() : Maybe.of(m.__value); >getOrElse(elseVal) < return this.isNothing() ? elseVal : this.__value; >getOrEmptyArray() < return this.getOrElse([]); >getOrNull() < return this.getOrElse(null); >isNothing() < return this.__value === null || this.__value === undefined; >map(fn) < return this.isNothing() ? Maybe.of(null) : Maybe.of(fn(this.__value)); >join() < return this.__value; >chain(fn) < return this.map(fn).join(); >ap(someOtherMaybe) < return someOtherMaybe.map(this.__value); >> 

Ну и, по сути, вся проверка на существование свойства объекта происходит банальным this.__value === null || this.__value === undefined .
А теперь попробуем монаду Maybe в деле:

Подключим необходимые модули, для работы с path используется библиотека rambda:

import < path >from 'rambda' 

Определяем объект testObj :

const testObj = < "a": < "b": < "c": "test" >> >

А затем создаем экземпляр нашего класса Maybe .

const maybeObj = Maybe.of(testObj)

Для того, чтобы получить строку, используется функция join() .
А здесь мы пытаемся получить значение свойства c :

const val = maybeObj .map(path(["a", "b", "c"])) .join()

Далее попытка обратиться к несуществующему свойству не приведет к возникновению ошибки, а просто вернет undefined .

Полный исходный код ниже:

import < path >from 'rambda' const testObj = < "a": < "b": < "c": "test" >> > const maybeObj = Maybe.of(testObj); console.log(maybeObj); console.log(maybeObj.join()); const val = maybeObj .map(path(["a", "b", "c"])) .join(); console.log(val); const valNothing = maybeObj .map(path(["test", "b", "c"])) .join(); console.log(valNothing);
  • https://jrsinclair.com/articles/2016/marvellously-mysterious-javascript-maybe-monad/
  • https://medium.com/@yyankowski/maybe-monad-in-javascript-to-save-us-from-the-hell-of-the-null-guard-clauses-bc9f9a1f291b
  • https://github.com/stoeffel/awesome-fp-js
  • https://tproger.ru/translations/better-javascript-code-with-fp-features/

Муки выбора платформы для блога

Previous article

Муки выбора платформы для блога

Иногда душа просит измарать бумагу, но, раз мы айтишники, то писать ну бумаге — это не наш метод, писать нужно в электронном виде. Ну а

У меня поломалась Raspberry Pi 3B

Следующая статья

У меня поломалась Raspberry Pi 3B

Как у любого уважающего себя айтишника у меня есть компьютер у кровати. Ноутбук не очень удобно, зато китайский сенсорный монитор, беспроводные клава и мышь, тонкий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *