> bracketOnError (openTempFile "." "temp")
> (\(tempName, tempHandle) -> do
> hClose tempHandle
> removeFile tempName)
> (\(tempName, tempHandle) -> do
> hPutStr tempHandle newTodoItems
> hClose tempHandle
> removeFile fileName
> renameFile tempName fileName)
Резюмируем наше решение. Мы написали функцию >dispatch
, отображающую команды на функции, которые принимают аргументы командной строки в виде списка и возвращают соответствующее действие ввода-вывода. Основываясь на значении первого аргумента, функция >dispatch
даёт нам необходимую функцию. В результате вызова этой функции мы получаем требуемое действие и выполняем его.
Давайте проверим, как наша программа работает:
>$ ./todo view todo.txt
>0 – Погладить посуду
>1 – Помыть собаку
>2 – Вынуть салат из печи
>$ ./todo add todo.txt "Забрать детей из химчистки"
>$ ./todo view todo.txt
>0 – Погладить посуду
>1 – Помыть собаку
>2 – Вынуть салат из печи
>3 – Забрать детей из химчистки
>$ ./todo remove todo.txt 2
>$ ./todo view todo.txt
>0 – Погладить посуду
>1 – Помыть собаку
>2 – Забрать детей из химчистки
Большой плюс такого подхода – легко добавлять новую функциональность. Добавить вариант определения функции >dispatch
, реализовать соответствующую функцию – и готово! В качестве упражнения можете реализовать функцию >bump
, которая примет файл и номер задачи и вернёт действие ввода-вывода, которое поднимет указанную задачу на вершину списка задач.
Работаем с некорректным вводом
Можно было бы дописать эту программу, улучшив сообщения об ошибках, возникающих при некорректных исходных данных. Начать можно с добавления варианта функции >dispatch
, который срабатывает при любой несуществующей команде:
>dispatch :: String -> [String] -> IO ()
>dispatch "add" = add
>dispatch "view" = view
>dispatch "remove" = remove
>dispatch command = doesntExist command
>doesntExist :: String -> [String] -> IO ()
>doesntExist command _ =
> putStrLn $ "Команда " ++ command ++ " не определена"
Также можно добавить варианты определения функций >add
, >view
и >remove
для случаев, когда программе передано неправильное количество аргументов. Например:
>add :: [String] -> IO ()
>add [fileName, todoItem] = appendFile fileName (todoItem ++ "\n")
>add _ = putStrLn "Команда add принимает в точности два аргумента"
Если функция >add
будет применена к списку, содержащему не два элемента, первый образец не сработает, поэтому пользователю будет выведено сообщение об ошибке. Аналогично дописываются функции >view
и >remove
.
Заметьте, что мы не обрабатываем все возможные случаи некорректного ввода. К примеру, программа «упадёт», если мы запустим её так: