В Haskell я бы обернул этот код в какую-то комбинацию монад, используя Maybe и Either's, и переводя и распространяя ошибки по мере необходимости.В конце концов, все это попадает в монаду ввода-вывода, где я могу вывести статус пользователю.
На другом языке я просто выкидываю исключение и ловлю в соответствующем месте.Непосредственная.Я не провожу много времени в когнитивном подвешенном состоянии, пытаясь выяснить, какая комбинация механизмов мне нужна.
Я бы не сказал, что вы обязательно подходите неправильно.Скорее ваша ошибка в том, что вы думаете, что эти два сценария различны;это не так.
"Просто бросить и поймать" равносильно навязыванию всей вашей программе той же концептуальной структуры, что и некоторая комбинация методов обработки ошибок в Haskell.Точная комбинация зависит от систем обработки ошибок языка, с которым вы ее сравниваете, что указывает на то, почему Haskell кажется более сложным: он позволяет вам смешивать и сопоставлять структуры обработки ошибок на основе потребностей, а непредоставляя вам неявное, подходящее по размеру решение.
Итак, если вам нужен определенный стиль обработки ошибок, используйте его;и вы используете его только для кода, который нуждается в этом.Код, который не нуждается в нем - из-за того, что он не генерирует и не обрабатывает соответствующие виды ошибок - помечается как таковой, что означает, что вы можете использовать этот код, не беспокоясь о создаваемой ошибке такого типа.
На предмет синтаксической неуклюжести, это неловкий предмет.Теоретически, это должно быть безболезненно, но:
- Haskell некоторое время был языком, ориентированным на исследования, и в первые дни многие вещи все еще были в движении, а полезные идиомы не были популяризированытем не менее, такой старый код, вероятно, будет плохим примером для подражания
- Некоторые библиотеки не настолько гибки, как они могли бы быть в том, как обрабатываются ошибки, либо из-за окаменения старого кода, как указано выше, либо просто из-за отсутствияпольский
- Я не знаю каких-либо руководств о том, как лучше структурировать новый код для обработки ошибок, поэтому новичков оставляют на своих собственных устройствах
Я думаю, что шансыВы как-то «делаете это неправильно» и можете избежать большей части этого синтаксического беспорядка, но, вероятно, не стоит ожидать, что вы (или любой обычный программист на Haskell) самостоятельно найдете лучшие подходы.
Что касается стеков монадных преобразователей, я думаю, что стандартный подход - это newtype
всего стека для вашего приложения, получения или реализации экземпляров дляr соответствующие классы типов (например, MonadError
), затем используйте функции класса типов, которые обычно не требуют lift
ing.Монадические функции, которые вы пишете для ядра вашего приложения, должны использовать стек newtype
d, поэтому также не нужно поднимать их.Я думаю, что единственная вещь с низким семантическим смыслом, которую вы не можете избежать, это liftIO
.
Работа с большими пакетами трансформаторов может быть настоящей головной болью, но только когда естьмного вложенных слоев различных преобразователей (свалите чередующиеся слои StateT
и ErrorT
с ContT
, посередине, а затем просто попытайтесь сказать мне, что на самом деле будет делать ваш код).Это редко то, чего вы на самом деле хотите.
Редактировать : В качестве небольшого добавления я хочу обратить внимание на более общий момент, который пришёл мне в голову при написании пары комментариев.
Как я заметил, и @sclv прекрасно продемонстрировали, что правильная обработка ошибок на самом деле очень сложна .Все, что вы можете сделать, это перемешать эту сложность, а не устранить ее, потому что независимо от того, что вы выполняете несколько операций, которые могут вызвать ошибки независимо, и ваша программа должна как-то обрабатывать каждую возможную комбинацию, даже если эта «обработка» должна просто упастьснова и умереть.
Тем не менее, Haskell действительно действительно существенно отличается от большинства языков в одном отношении: как правило, обработка ошибок является явным и первоклассным , что означаетчто все открыто и им можно свободно манипулировать.Обратной стороной этого является потеря неявной обработки ошибок, а это означает, что даже если все, что вам нужно, это напечатать сообщение об ошибке и умереть, вы должны сделать это явно.Так что на самом деле делать обработку ошибок проще в Haskell, потому что это первоклассные абстракции для него, но игнорировать ошибки сложнее.Однако такого рода обработка ошибок «все руки покидает корабль» почти никогда не корректна при любом реальном использовании в производственных целях, поэтому кажется, что неловкость отбрасывается в сторону.
Так что, хотя поначалу все сложнее, когда вам нужно явно разобраться с ошибками, важно помнить, что - это все, что нужно .Как только вы научитесь использовать правильные абстракции обработки ошибок, сложность в значительной степени достигнет плато и не станет значительно сложнее по мере расширения программы;и чем больше вы используете эти абстракции, тем более естественными они становятся.