Изучай Haskell во имя добра! (Липовача) - страница 137

>Погладить посуду

>Вынуть салат из печи

Круто! Удалим ещё что-нибудь:

>$ ./deletetodo

>Ваши задания:

>0 – Погладить посуду

>1 – Вынуть салат из печи

>Что вы хотите удалить?

>0

Проверяя файл с заданиями, убеждаемся, что осталось только одно:

>$ cat todo.txt

>Вынуть салат из печи

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

Уборка

Чтобы гарантировать удаление временного файла, воспользуемся функцией >bracketOnError из модуля >Control.Exception. Она очень похожа на >bracket, но если последняя получает ресурс и гарантирует, что освобождение ресурса будет выполнено всегда, то функция >bracketOnError выполнит завершающие действия только в случае возникновения исключения. Вот исправленный код:

>import System.IO

>import System.Directory

>import Data.List

>import Control.Exception


>main = do

>   contents <– readFile "todo.txt"

>   let todoTasks = lines contents

>       numberedTasks = zipWith (\n line –> show n ++ " – " ++ line)

>                               [0..] todoTasks

>   putStrLn "Ваши задания:"

>   mapM_ putStrLn numberedTasks

>   putStrLn "Что вы хотите удалить?"

>   numberString <– getLine

>   let number = read numberString

>       newTodoItems = unlines $ delete (todoTasks !! number) todoTasks

>   bracketOnError (openTempFile "." "temp")

>      (\(tempName, tempHandle) –> do

>            hClose tempHandle

>            removeFile tempName)

>      (\(tempName, tempHandle) –> do

>            hPutStr tempHandle newTodoItems

>            hClose tempHandle

>            removeFile "todo.txt"

>            renameFile tempName "todo.txt")

Вместо обычного использования функции >openTempFile мы заключаем её в >bracketOnError. Затем пишем, что должно произойти при возникновении исключения: мы хотим закрыть и удалить временный файл. Если же всё нормально, пишем новый список заданий во временный файл; все эти строки остались без изменения. Мы выводим новые задания, удаляем исходный файл и переименовываем временный.

Аргументы командной строки

Если вы пишете консольный скрипт или приложение, то вам наверняка понадобится работать с аргументами командной строки. К счастью, в стандартную библиотеку языка Haskell входят удобные функции для работы с ними.

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