Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Ещё больше шалостей со списком делСодержание книги
Поиск на нашем сайте В предыдущих примерах мы писали отдельные программы для до- бавления и удаления заданий в списке дел. Теперь мы собираемся объединить их в новое приложение, а что ему делать, будем указы- вать в командной строке. Кроме того, позаботимся о том, чтобы программа смогла работать с разными файлами – не только todo.txt. Назовём программу просто todo, она сможет делать три разные вещи: ® просматривать задания; ® добавлять задания; ® удалять задания.
Для добавления нового задания в список дел в файле todo.txt мы будем писать: $./todo add todo.txt "Найти магический меч силы"
Просмотреть текущие задания можно будет командой view: $./todo view todo.txt
Для удаления задания потребуется дополнительно указать его индекс: $./todo remove todo.txt 2
Многозадачный список задач
Начнём с реализации функции, которая принимает команду в виде строки (например, "add" или "view") и возвращает функцию, кото- раявсвоюочередьпринимаетсписокаргументовивозвращаетдейс- твие ввода-вывода, выполняющее в точности то, что необходимо: import System.Environment import System.Directory import System.IO import Data.List import Control.Exception
dispatch:: String -> [String] –> IO () dispatch "add" = add
dispatch "view" = view dispatch "remove" = remove Функция main будет выглядеть так:
main = do
(command:argList) <- getArgs dispatch command argList Первым делом мы получаем аргументы и связываем их со спис- ком (command:argsList). Таким образом, первый аргумент будет связан с именем command, а все остальные – со списком argList. В следующей строке к переменной commands применяется функ- ция dispatch, результатом которой может быть одна из функций add, view или remove. Затем результирующая функция применяется к списку аргументов argList. Предположим, программа запущена со следующими парамет- рами:
$./todo add todo.txt "Найти магический меч силы" Тогда значением command будет "add", а значением argList – спи- сок ["todo.txt", "Найти магический меч силы"]. Поэтому сработает первый вариант определения функции dispatch и будет возвраще- на функция add. Применяем её к argList, результатом оказывается действие ввода-вывода, добавляющее новое задание в список.
Теперь давайте реализуем функции add, view и remove. Начнём с первой из них: add:: [String] –> IO ()
add [fileName, todoItem] = appendFile fileName (todoItem ++ "\n") При вызове
$./todo add todo.txt "Найти магический меч силы" функции add будет передан список ["todo.txt", "Найти магический меч силы"]. Поскольку пока мы не обрабатываем некорректный ввод, достаточно будет сопоставить аргумент функции add с двухэлемен- тным списком. Результатом функции будет действие ввода-вывода, добавляющее строку вместе с символом конца строки в конец фай- ла. Далее реализуем функциональность просмотра списка. Если мы хотим просмотреть элементы списка, то вызываем программу так: todo view todo.txt. В первом сопоставлении с образцом идентифика- тор command будет связан со строкой view, а идентификатор argList будет равен ["todo.txt"].
Вот код функции view: view:: [String] –> IO () view [fileName] = do contents <– readFile fileName let todoTasks = lines contents numberedTasks = zipWith (\n line –> show n ++ " – " ++ line) [0..] todoTasks
putStr $ unlines numberedTasks Программа, которая удаляла задачу из списка, производила практически те же самые действия: мы отображали список задач, чтобы пользователь мог выбрать, какую из них удалить. Но в этой функции мы просто отображаем список.
Ну и наконец реализуем функцию remove. Функция будет очень похожа на программу для удаления элемента, так что если вы не понимаете, как работает функция удаления, прочитайте поясне- ния к её определению. Основное отличие – мы не задаём жёстко имя файла, а получаем его как аргумент. Также мы не спрашиваем у пользователя номер задачи для удаления – его мы также получаем в виде аргумента. remove:: [String] -> IO () remove [fileName, numberString] = do contents <- readFile fileName let todoTasks = lines contents 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 fileName renameFile tempName fileName) Мы открываем файл, полное имя которого задаётся в иденти- фикаторе fileName, открываем временный файл, удаляем строку по индексу, записываем во временный файл, удаляем исходный файл и переименовываем временный в fileName. Приведем полный лис- тинг программы во всей её красе:
import System.Environment import System.Directory import System.IO import Control.Exception import Data.List
dispatch:: String -> [String] -> IO () dispatch "add" = add dispatch "view" = view dispatch "remove" = remove
main = do
(command:argList) <- getArgs dispatch command argList
add:: [String] -> IO () add [fileName, todoItem] = appendFile fileName (todoItem ++ "\n")
view:: [String] -> IO () view [fileName] = do contents <- readFile fileName let todoTasks = lines contents numberedTasks = zipWith (\n line -> show n ++ " – " ++ line) [0..] todoTasks putStr $ unlines numberedTasks
remove:: [String] -> IO () remove [fileName, numberString] = do contents <- readFile fileName let todoTasks = lines contents 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 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, которая примет файл и номер задачи и вернёт действие ввода-вывода, которое поднимет указанную задачу на вершину списка задач.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Последнее изменение этой страницы: 2017-02-17; просмотров: 236; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.21 (0.006 с.) |