Вот у меня такой странный вопрос: почему IO функции выбрасывают ошибки ? Я имею в виду зачем делать error в IO вообще ?
Ведь любой ввод-вывод в хаскеле - это вызов внешних сишных функций, как и в любой другом языке. Сишная функция по определению не выбрасывает иключений, она лишь возвращает не нулевое значение, что является признаком возникновения исключительной ситуации.
В документации по хаскелю сказано, что выбрасывание ошибок нужно делать, когда дальнейшее выполнение программы не имеет смысла. Например ошибка паттерн матчинга - есть ошибка программы, ведь ADT в хаскеле - практически часть алгоритма, и поэтому единственным способом избавления от ошибки является правка кода. Все остальные ошибки, к которым относятся все ошибки ввода-вывода являются не ошибками, а исключениями, и должны обрабатыватся вещами типа EitherT.
Ну действительно: разве это ошибка, когда файл не удается прочесть ? Разве должна программа из-за этого падать ? Я понимаю, что есть средства обработки ошибок, но эти средства позволяют лишь отловить ошибку и сделать некие действия, но не более. Ведь если прерывать вычисление, то теряются все монадные профиты.
Представьте, вот есть список действий IO, ваша задача выполнить все действия и сложить в список результат только тех, которые выполнились без ошибок, а те, что с ошибкой, просто игнорировать. Если решать это с помощью EitherT, то решение элементарное
ignoreErrors :: [EitherT IO a] -> IO [a]
ignoreErrors x = do
y <- sequence $ map runEitherT x
return $ rights y
При этом монада нам гарантирует, что никакая ленивость не помешает нам отловить все ошибки ввода-вывода которые могут возникнуть, что все монадические действия вычислятся как минимум до конструктора Either, ведь могут существовать и другие исключения, не только те, что связаны с вводом-выводом, но и некоторые исключения в вычислениях. Все это будет отловлено в тот момент, когда мы просто паттернматчим результат runEitherT с Left или с Right.
Если задача стоит просто выполнить действия и гарантировать, отсутсвтвие исключений во всех вычислениях, то это просто sequence или sequence_, в зависимости от того, нужен нам результат вычислений, или нет.
Обрабатывать ошибки с помощью отлова ошибок в тотально ленивом языке - не самая классная идея, ведь у нас нет гарантии вычисления выражения до той глубины, в которой станет ясно, что ни одна ошибка больше не выбросится, хаскель не отслеживает использование error и не форсирует ее вычисление до тех пор, пока это не станет нужно для другого какого - нибудь вычисления.
Отсюда у меня вопрос: о чем думали создатели хаскеля, когда вообще включали error в стандартную библиотеку, использовали ее во всех функциях (деление на ноль) и давали пользователю ей пользоваться. Взгляните на все библиотеки, они все используют выбрасывание ошибок, вместо обработки исключений. Либо я чего-то не понимаю, и выбрасывать ошибку - очень удобно и правильно, либо это фейл проектировщиков ?
Дискач.
PS. haters gonna hate