Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Манипулируем файловой системой

Поиск

 
 

Теперь, когда мы можем передвигаться по нашей файловой систе- ме, ею легко манипулировать. Вот функция, которая переименовы- вает находящийся в данный момент в фокусе файл или каталог:

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

Перевод с английского Леушин Д., Синицын А.,

Арсанукаев Я.

Научные редакторы Душкин Р. В., Брагилевский В. Н.

Корректор Синяева Г. И.

Верстка Паранская Н. В.

Дизайн обложки Мовчан А. Г.

 
Подписано в печать 23.02.2012. Формат 60´901/. Гарнитура «NewBaskervilleC». Печать офсетная.

Усл. печ. л. 30.02. Тираж 500 экз.

 

Web-сайт издательства: www.dmk-press.ru




Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 194; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.219.247.59 (0.007 с.)