Как монады обработки ошибок, такие как Eithers, достигают ссылочной прозрачности? - PullRequest
2 голосов
/ 15 апреля 2019

Из прочтения о FP я понимаю, что преимущества устранения побочных эффектов заключаются в том, что если все наши функции являются чистыми / имеют ссылочную прозрачность (то, что может быть достигнуто только без побочных эффектов), то наши функции легче тестировать , отладка, повторное использование и более модульные.

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

Что меня смущает, так это то, как именно монады достигают этого. Предположим, у меня есть этот код с использованием scalaz

def couldThrowException: Exception \/ Boolean = ??
val f  = couldThrowException()
val g = couldThrowException()

Поскольку couldThrowException может возвращать исключение, нет гарантии, что f и g будут одинаковыми. f может быть \/-(true), а g может быть -\/(NullPointerException). Поскольку couldThrowException может возвращать разные значения с одним и тем же вводом, это не чистая функция. Не было ли смысла использовать монады для поддержания чистоты наших функций?

1 Ответ

5 голосов
/ 15 апреля 2019

f() и g() должны вычислять одно и то же значение при одинаковом входном сигнале.

В чистом FP ​​функция без аргументов должна обязательно вычислять один и тот же результат каждыйраз это называется.Так что это не чистый FP, если ваш couldThrowException иногда возвращает \/-(true), а иногда -\/(NullPointerException).

Имеет смысл возвращать Either, если couldThrowException принимает параметр.Если это чистая функция, она будет иметь ссылочную прозрачность, поэтому некоторые входные данные всегда будут приводить к \/-(true), а некоторые входные данные всегда будут приводить к -\/(NullPointerException).

В Scala вы вполне можете использовать функцию, которая не чистый, а не референтный прозрачный.Возможно, это класс Java.Возможно, он использует не чистую часть Scala.

Но я думаю, вы заинтересованы в соединении между миром чистого FP и нечистыми библиотеками.Классическим примером этого является IO.println может произойти сбой по разным причинам - разрешения, файловая система переполнена и т. Д.

Классический способ справиться с этим в FP - это использовать функцию ввода-вывода, которая принимает состояние "world" в качестве входного параметра,и возвращает как результат вызова IO, так и новое «мировое» состояние.Состояние может быть «поддельным» значением, подкрепленным библиотечным кодом на нечистом языке, но это означает, что каждый раз, когда вы вызываете функцию, вы передаете другое состояние, поэтому оно прозрачно для ссылок.

Часто монада используется для инкапсуляции «мира».

Вы можете многое узнать об этом подходе, прочитав о монаде Haskell IO.

Core Scala IO не совсем чист,так что println может выдавать и исключение, и, следовательно, как вы заметили, не полностью прозрачно по ссылкам. Scalaz предоставляет монаду ввода-вывода, похожую на монаду Haskell.

Одна вещь, на которую следует обратить внимание, потому что это сбивает с толку многих новичков: нет ничего о подходе "World", который требует монады, и IOне легко взглянуть на монаду, когда впервые узнаешь, что такое монада и почему она полезна.

...