>goLeft (Node x l r, bs) = (l, (LeftCrumb x r):bs)
Как вы можете видеть, она очень похожа на нашу предыдущую функцию >goLeft
, но вместо того чтобы просто добавлять код >L
в «голову» нашего списка «хлебных крошек», мы добавляем туда значение >LeftCrumb
, чтобы показать, что мы пошли влево. Мы также снабжаем наше значение >LeftCrumb
элементом узла, из которого мы переместились (то есть значением >x
), и правым поддеревом, которое мы решили не посещать.
Обратите внимание: эта функция предполагает, что текущее дерево, находящееся в фокусе, – не >Empty
. Пустое дерево не содержит никаких поддеревьев, поэтому если мы попытаемся пойти влево из пустого дерева, возникнет ошибка. Причина в том, что сравнение значения типа >Node
с образцом будет неуспешным, и нет образца, который заботится о конструкторе >Empty
.
Функция >goRight
аналогична:
>goRight :: (Tree a, Breadcrumbs a) –> (Tree a, Breadcrumbs a)
>goRight (Node x l r, bs) = (r, (RightCrumb x l):bs)
Ранее мы могли двигаться влево или вправо. То, чем мы располагаем сейчас, – это возможность действительно возвращаться вверх, запоминая информацию о родительских узлах и путях, которые мы не посетили. Вот определение функции >goUp
:
>goUp :: (Tree a, Breadcrumbs a) –> (Tree a, Breadcrumbs a)
>goUp (t, LeftCrumbx r:bs) = (Node x t r, bs)
>goUp (t, RightCrumb x l:bs) = (Node x l t, bs)
Мы фокусируемся на дереве >t
и проверяем последнее значение типа >Crumb
. Если это значение равно >LeftCrumb
, мы строим новое дерево, используя наше дерево >t
в качестве левого поддерева и информацию о правом поддереве и элементе, которые мы не посетили, чтобы заполнить остальные части >Node
. Поскольку мы «переместились обратно» и подняли последнюю «хлебную крошку», а затем использовали её, чтобы воссоздать родительское дерево, в новом списке эта «хлебная крошка» не содержится.
Обратите внимание, что данная функция вызывает ошибку, если мы уже находимся на вершине дерева и хотим переместиться выше. Позже мы используем монаду >Maybe
, чтобы представить возможную неудачу при перемещении фокуса.
С парой, состоящей из значений типов >Tree
>a
и >Breadcrumbs
>a
, у нас есть вся необходимая информация для восстановления дерева; кроме того, у нас есть фокус на поддереве. Эта схема позволяет нам легко двигаться вверх, влево и вправо.
Пару, содержащую часть структуры данных в фокусе и её окружение, называют застёжкой, потому что перемещение нашего фокуса вверх и вниз по структуре данных напоминает работу застёжки-молнии на брюках. Поэтому круто будет создать такой синоним типа:
>type Zipper a = (Tree a, Breadcrumbs a)