Одной из самых разрекламированных функций Elm является отсутствие исключений во время выполнения. Но я бы поспорил, что:

  1. В Elm действительно есть исключения времени выполнения (они просто не называют их так).
  2. Elm заставляет вас обрабатывать эти исключения немедленно и на месте (в отличие от того, чтобы позволить им всплывать, чтобы их обрабатывала функция верхнего уровня, как в случае с Java, C# или JavaScript).
  3. Это усложняет чтение вашего кода.

Раньше функция C использовала возвращаемое значение для возврата либо действительного результата (скажем, числа от 1 до 100), либо состояния ошибки (скажем, -1). Это было некрасиво, потому что после каждой строки кода нужно было проверять возвращаемое значение на наличие ошибки. Обработка исключений была настолько переплетена с основной логикой вашего приложения, что ее стало невозможно прочитать. Было бы больше проверки ошибок, чем реальной бизнес-логики.

Введите Java и C#. Они добавили try/catch. Блок catch позволяет вам поместить всю обработку исключений в конец блока (вместо того, чтобы чередовать его с вашей бизнес-логикой). Java также позволяет делегировать обработку исключения вызывающей функции. Таким образом, исключения во время выполнения могут всплывать, что позволяет обрабатывать их выше по стеку вызовов. Это отличная вещь. Это делает код более читабельным и удобным для сопровождения.

Так что Elm, похоже, возвращает нас во времена C.

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

Но в Elm доступ к массиву возвращает Maybe. И поэтому вы должны разобраться с этим «исключением» (вот что это такое, даже если они не используют этот термин в Elm) сразу, на месте. Никакого пузырения. То же самое относится и к синтаксическому анализу: decodeString int «42» не возвращает int. Он возвращает результат. Вы должны иметь дело с ошибкой синтаксического анализа на месте.

Подводя итог, я бы сказал, что каждый раз, когда вам приходится иметь дело с «Может быть» или «Результатом», вы, по сути, занимаетесь обработкой исключений. Единственное отличие состоит в том, что вам не разрешено откладывать эту обработку на функцию верхнего уровня (т. е. позволять ей подниматься вверх).

Вот еще один способ взглянуть на это. Представьте, что Java решила сделать ArrayIndexOutOfBoundsException, NullPointerException и NumberFormatException проверенными исключениями вместо того, чем они являются сейчас (непроверенными исключениями). Это была бы лучшая аналогия с тем, что делает Elm. Я бы сказал, что это сделает ваш код менее надежным, а не более. Почему? Потому что вы закончите с кодом, который выглядит так:

int foo(String s){
  try{
    return Integer.parseInt(s) * 2;
  }
  catch(NumberFormatException e){
    return 0;
  }
}

Я бы сказал, что это делает ваш код менее надежным. Это будет лучшей альтернативой:

int foo(String s){
  return Integer.parseInt(s) * 2;
}

Второй вариант — это то, что мы называем быстрая ошибка. Первый вариант возвращает ноль. Что переводит вашу программу в недопустимое состояние.

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

Интересно отметить: C# (пришедший после Java) решил не включать проверенные исключения, а только непроверенные исключения. Кроме того, большинство новых библиотек в экосистеме Java, по-видимому, предпочитают использовать исключительно непроверенные исключения. Нет проверенных исключений.

Элм решил пойти в другом направлении. Есть только проверенные исключения.

Возможно, мне нужно еще немного времени с Elm, но исходя из моего текущего понимания, я бы предпочел каким-то образом позволить исключениям всплывать. ИМО, обработка их «встроенной» служит только для загромождения вашего кода.