Изучай Haskell во имя добра! (Липовача) - страница 286

>ghci> let newFocus = farLeft –: attach (Node 'Z' Empty Empty)

Значение >newFocus теперь сфокусировано на дереве, которое мы только что прикрепили, а остальная часть дерева находится в «хлебных крошках» в вывернутом наизнанку виде. Если бы мы использовали функцию >goUp для прохода всего пути к вершине дерева, оно было бы таким же деревом, как и >freeTree, но с дополнительным символом >'Z' на дальнем левом краю.

Идём прямо на вершину, где воздух чист и свеж!

Создать функцию, которая проходит весь путь к вершине дерева, независимо от того, на чём мы фокусируемся, очень просто. Вот она:

>topMost :: Zipper a –> Zipper a

>topMost (t, []) = (t, [])

>topMost z = topMost (goUp z)

Если наша расширенная тропинка из «хлебных крошек» пуста, это значит, что мы уже находимся в корне нашего дерева, поэтому мы просто возвращаем текущий фокус. В противном случае двигаемся вверх, чтобы получить фокус родительского узла, а затем рекурсивно применяем к нему функцию >topMost.

Итак, теперь мы можем гулять по нашему дереву, двигаясь влево, вправо и вверх, применяя функции >modify и >attach во время нашего путешествия. Затем, когда мы покончили с нашими изменениями, используем функцию >topMost, чтобы сфокусироваться на вершине дерева и увидеть произведённые нами изменения в правильной перспективе.

Фокусируемся на списках

Застёжки могут использоваться почти с любой структурой данных, поэтому неудивительно, что они работают с подсписками списков. В конце концов, списки очень похожи на деревья, только узел дерева содержит (или не содержит) элемент и несколько поддеревьев, а узел списка – элемент и лишь один подсписок. Когда мы реализовывали свои собственные списки в главе 7, то определили наш тип данных вот так:

>data List a = Empty | Cons a (List a) deriving (Show, Read, Eq, Ord)

Сравните это с определением нашего бинарного дерева – и легко увидите, что списки можно воспринимать в качестве деревьев, где каждый узел содержит лишь одно поддерево.

Список вроде >[1,2,3] может быть записан как >1:2:3:[]. Он состоит из «головы» списка равной >1 и «хвоста», который равен >2:3:[]. 2:3:[] также имеет «голову», которая равна >2, и «хвост», который равен >3:[]. Для >3:[] «голова» равна >3, а «хвост» является пустым списком >[].



Давайте создадим застёжку для списков. Чтобы изменить фокус на подсписках списка, мы перемещаемся или вперёд, или назад (тогда как при использовании деревьев мы перемещались вверх, влево или вправо). Помещённой в фокус частью будет подсписок, а кроме того, мы будем оставлять «хлебные крошки» по мере нашего движения вперёд.