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

>   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.

Заметьте, что мы не обрабатываем все возможные случаи некорректного ввода. К примеру, программа «упадёт», если мы запустим её так: