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)
, которое имеет контекст возможной неудачи) и передаёт его в функцию, обеспечивая при этом обработку контекста. Так что, как и наш канатоходец, мы отдадим все наши старые операторы –:
в счёт приобретения операторов >>=
. Затем мы вновь сможем сцеплять наши функции! Смотрите, как это работает:
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 и его идиом. Хотя при изучении этого языка всегда открывается что-то новое, вы теперь сможете писать классный код, а также читать и понимать код других людей. Так что скорее приступайте к делу! Увидимся в мире программирования!