Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Манипулируем файловой системой↑ ⇐ ПредыдущаяСтр 60 из 60 Содержание книги
Поиск на нашем сайте
Теперь, когда мы можем передвигаться по нашей файловой систе- ме, ею легко манипулировать. Вот функция, которая переименовы- вает находящийся в данный момент в фокусе файл или каталог: fsRename:: Name –> FSZipper –> FSZipper fsRename newName (Folder name items, bs) = (Folder newName items, bs) fsRename newName (File name dat, bs) = (File newName dat, bs) Давайте переименуем наш каталог "pics" в "cspi": ghci> let newFocus = (myDisk, []) –: fsTo "pics" –: fsRename "cspi" –: fsUp Мы спустились к каталогу "pics", переименовали его, а затем поднялись обратно вверх. Как насчёт функции, которая создаёт новый элемент в текущем каталоге? Встречайте: fsNewFile:: FSItem –> FSZipper –> FSZipper fsNewFile item (Folder folderName items, bs) = (Folder folderName (item:items), bs) Проще пареной репы! Обратите внимание, что если бы мы по- пытались добавить элемент, но фокусировались бы на файле, а не на каталоге, это привело бы к аварийному завершению программы. Давайте добавим в наш каталог "pics" файл, а затем поднимем- ся обратно к корню:
ghci> let newFocus = (myDisk, []) –: fsTo "pics" –: fsNewFile (File "heh.jpg" "лол") –: fsUp Что действительно во всём этом здорово, так это то, что когда мы изменяем нашу файловую систему, наши изменения на самом деле не производятся на месте – напротив, функция возвращает со- вершенно новую файловую систему. Таким образом, мы имеем до- ступ к нашей прежней файловой системе (в данном случае myDisk), а также к новой (первый компонент newFocus). Используя застёжки, мы бесплатно получаем контроль версий. Мы всегда можем обратиться к старым версиям структур данных даже после того, как изменили их. Это не уникальное свойство за- стёжек; оно характерно для языка Haskell в целом, потому что его структуры данных неизменяемы. При использовании застёжек, однако, мы получаем возможность легко и эффективно обходить наши структуры данных, так что неизменность структур данных языка Haskell действительно начинает сиять во всей красе!
Осторожнее – смотрите под ноги! До сих пор при обходе наших структур данных – будь они бинарны- ми деревьями, списками, или файловыми системами – нам не было дела до того, что мы прошагаем слишком далеко и упадём. Напри- мер, наша функция goLeft принимает застёжку бинарного дерева и передвигает фокус на его левое поддерево: goLeft:: Zipper a –> Zipper a goLeft (Node x l r, bs) = (l, LeftCrumb x r:bs) Но что если дерево, с которого мы сходим, является пустым? Что если это не значение Node, а Empty? В этом случае мы получили бы ошибку времени исполнения, потому что сопоставление с об- разцом завершилось бы неуспешно, а образец для обработки пусто- го дерева, у которого нет поддеревьев, мы не создавали. До сих пор мы просто предполагали, что никогда не пытались бы навести фокус на левое поддерево пустого дерева, так как его левого поддерева просто не существует. Но переход к левому подде- реву пустого дерева не имеет какого-либо смысла, и мы до сих пор это удачно игнорировали. ОСТОРОЖНЕЕ – СМОТРИТЕ ПОД НОГИ 487 Ну или вдруг мы уже находимся в кор- не какого-либо дерева, и у нас нет «хлеб- ных крошек», но мы всё же пытаемся переместиться вверх? Произошло бы то же самое! Кажется, при использовании застёжек каждый наш шаг может стать последним (не хватает только зловещей музыки). Другими словами, любое пере- мещение может привести к успеху, но также может привести и к неудаче. Вам это что-нибудь напоминает? Ну конечно же: монады! А конкретнее, монаду Maybe, которая добавляет к обычным значени- ям контекст возможной неудачи. Давайте используем монаду Maybe, чтобы добавить к нашим перемещениям контекст возможной не- удачи. Мы возьмём функции, которые работают с нашей застёжкой для двоичных деревьев, и превратим в монадические функции. Сначала давайте позаботимся о возможной неудаче в функци- ях goLeft и goRight. До сих пор неуспешное окончание выполнения функций, которые могли окончиться неуспешно, всегда отражалось в их результате, и этот пример – не исключение. Вот определения функций goLeft и goRight с добавленной воз- можностью неудачи: goLeft:: Zipper a –> Maybe (Zipper a) goLeft (Node x l r, bs) = Just (l, LeftCrumb x r:bs) goLeft (Empty, _) = Nothing
goRight:: Zipper a –> Maybe (Zipper a) goRight (Node x l r, bs) = Just (r, RightCrumb x l:bs) goRight (Empty, _) = Nothing Теперь, если мы попытаемся сделать шаг влево относительно пустого дерева, мы получим значение Nothing! ghci> goLeft (Empty, []) Nothing ghci> goLeft (Node 'A' Empty Empty, []) Just (Empty, [LeftCrumb 'A' Empty])
Выглядит неплохо! Как насчёт движения вверх? Раньше возни- кала проблема, если мы пытались пойти вверх, но у нас больше не было «хлебных крошек», что значило, что мы уже находимся в кор- не дерева. Это функция goUp, которая выдаст ошибку, если мы вый- дем за пределы нашего дерева: goUp:: Zipper a –> Zipper a goUp (t, LeftCrumbx r:bs) = (Node x t r, bs) goUp (t, RightCrumb x l:bs) = (Node x l t, bs) Давайте изменим её, чтобы она завершалась неудачей мягко: goUp:: Zipper a –> Maybe (Zipper a) goUp (t, LeftCrumbx r:bs) = Just (Node x t r,bs) goUp (t, RightCrumb x l:bs) = Just (Node x l t, bs) goUp (_, []) = Nothing Если у нас есть хлебные крошки, всё в порядке, и мы возвра- щаем успешный новый фокус. Если у нас нет хлебных крошек, мы возвращаем неудачу. Раньше эти функции принимали застёжки и возвращали застёж- ки, что означало, что мы можем сцеплять их следующим образом для осуществления обхода: gchi> let newFocus = (freeTree, []) –: goLeft –: goRight Но теперь вместо того, чтобы возвращать значение типа Zipper a, они возвращают значение типа Maybe (Zipper a), и сцеп- ление функций подобным образом работать не будет. У нас была похожая проблема, когда в главе 13 мы имели дело с нашим канато- ходцем. Он тоже проходил один шаг за раз, и каждый из его шагов мог привести к неудаче, потому что несколько птиц могли призем- литься на одну сторону его балансировочного шеста, что приводи- ло к падению. Теперь шутить будут над нами, потому что мы – те, кто произво- дит обход, и обходим мы лабиринт нашей собственной разработки. К счастью, мы можем поучиться у канатоходца и сделать то, что сде- лал он: заменить обычное применение функций оператором >>=. Он берёт значение с контекстом (в нашем случае это значение типа Maybe (Zipper a), которое имеет контекст возможной неудачи) и пе- редаёт его в функцию, обеспечивая при этом обработку контекста. Так что, как и наш канатоходец, мы отдадим все наши старые опера- БЛАГОДАРЮ ЗА ТО, ЧТО ПРОЧИТАЛИ! 489
торы –: в счёт приобретения операторов >>=. Затем мы вновь смо- жем сцеплять наши функции! Смотрите, как это работает: ghci> let coolTree = Node 1 Empty (Node 3 Empty Empty) ghci> return (coolTree, []) >>= goRight Just (Node 3 Empty Empty,[RightCrumb 1 Empty]) ghci> return (coolTree, []) >>= goRight >>= goRight Just (Empty,[RightCrumb 3 Empty,RightCrumb 1 Empty]) ghci> return (coolTree, []) >>= goRight >>= goRight >>= goRight Nothing Мы использовали функцию return, чтобы поместить застёжку в конструктор Just, а затем прибегли к оператору >>=, чтобы пере- дать это дело нашей функции goRight. Сначала мы создали дерево, которое в своей левой части имеет пустое поддерево, а в правой – узел, имеющий два пустых поддерева. Когда мы пытаемся пойти вправо один раз, результатом становится успех, потому что опера- ция имеет смысл. Пойти вправо во второй раз – тоже нормально. В итоге мы получаем фокус на пустом поддереве. Но идти вправо третий раз не имеет смысла: мы не можем пойти вправо от пустого поддерева! Поэтому результат – Nothing. Теперь мы снабдили наши деревья «сеткой безопасности», ко- торая поймает нас, если мы свалимся. (Ух ты, хорошую метафору я подобрал.) ПРИМЕЧАНИЕ. В нашей файловой системе также имеется мно- го случаев, когда операция может завершиться неуспешно, как, например, попытка сфокусироваться на несуществующем файле или каталоге. В качестве упражнения вы можете снабдить нашу файловую систему функциями, которые завершаются неудачей мягко, используя монаду Maybe. Благодарю за то, что прочитали! ...Или, по крайней мере, пролистали до последней страницы! Я на- деюсь, вы нашли эту книгу полезной и весёлой. Я постарался дать вам хорошее понимание языка Haskell и его идиом. Хотя при изу- чении этого языка всегда открывается что-то новое, вы теперь смо- жете писать классный код, а также читать и понимать код других людей. Так что скорее приступайте к делу! Увидимся в мире прог- раммирования! Миран Липовача
Изучай Haskell во имя добра Главный редактор Мовчан Д. А. dm@dmk-press.ru Перевод с английского Леушин Д., Синицын А., Арсанукаев Я. Научные редакторы Душкин Р. В., Брагилевский В. Н. Корректор Синяева Г. И. Верстка Паранская Н. В. Дизайн обложки Мовчан А. Г. Усл. печ. л. 30.02. Тираж 500 экз.
Web-сайт издательства: www.dmk-press.ru
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 194; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.219.247.59 (0.007 с.) |