Ответ 1
Очистка при наличии исключений
Однако, неспособность предвидеть и реагировать на прерывание пользователя, такое как это, может считаться ошибкой. Поэтому, возможно, программа должна поймать это и обработать его надлежащим образом, сделав необходимую очистку перед выходом.
В некотором смысле вы правы - программист должен предвидеть исключения. Но не поймать их. Вместо этого вы должны использовать исключительные функции, такие как bracket
.
Например:
import Control.Exception
data Resource
acquireResource :: IO Resource
releaseResource :: Resource -> IO ()
workWithResource = bracket acquireResource releaseResource $ \resource -> ...
Таким образом, ресурсы будут очищены независимо от того, будет ли программа отменена с помощью Ctrl + C.
Если исключения превышают верхний уровень?
Теперь я хотел бы обратиться к другому вашему заявлению:
Основная позиция заключается в том, что в хорошо продуманном приложении исключения не должны выходить на верхний уровень.
Я бы сказал, что в хорошо продуманном приложении исключения - прекрасный способ прервать. Если с этим возникают какие-либо проблемы, вы делаете что-то неправильно (например, хотите выполнить действие очистки в конце main
), но это должно быть сделано в bracket
!).
Вот что я часто делаю в своих программах:
-
Определите тип данных, который представляет любую возможную ошибку - все, что может пойти не так. Некоторые из них часто переносят другие исключения.
data ProgramError = InputFileNotFound FilePath IOException | ParseError FilePath String | ...
-
Определите, как печатать ошибки удобным для пользователя способом:
instance Show ProgramError where show (InputFileNotFound path e) = printf "File '%s' could not be read: %s" path (show e) ...
-
Объявить тип как исключение:
instance Exception ProgramError
-
Бросьте эти исключения в программу всякий раз, когда мне это нравится.
Должны ли я перехватывать исключения?
Исключения, которые вы ожидаете, должны быть пойманы и завернуты (например, в InputFileNotFound
), чтобы дать им больше контекста. Как насчет исключений, которые вы не ожидаете?
Я вижу некоторое значение при печати "это ошибка" для пользователей, так что они сообщают о проблеме вам. Если вы это сделаете, вы должны ожидать UserInterrupt
- это не ошибка, как вы говорите. Как вы должны относиться к ThreadKilled
, зависит от вашего приложения - буквально, ожидаете ли вы этого?
Это, однако, ортогонально "хорошему дизайну" и больше зависит от того, на каких пользователях вы нацеливаетесь, что вы ожидаете от них и чего они ожидают от вашей программы. Ответ может варьироваться от просто распечатки исключения до диалога, в котором говорится: "Нам очень жаль, вы хотели бы представить отчет разработчикам?".