Для чего нужны шрамы?

В статье под названием "Застежка-молния" Уэта он также упоминает шрамы как изменение молнии. По сравнению с молниями, которые стали довольно хорошо известны в сообществе Haskell, шрамы в значительной степени неслыханны. Информация о них очень мало в самой статье и в любом месте в Интернете из того, что я мог найти.

Поэтому я должен спросить: они просто не полезны вообще или есть что-то полезное, но большинство людей просто не знают о них?

Ответы

Ответ 1

Это просто незначительная корректировка типа дерева, чтобы сделать определенные операции более эффективными.

Бумага фокусируется (ха-ха) на розовых деревьях - деревьях, узлы которых имеют произвольное количество детей. Код из статьи находится в OCaml, но очень просто перевести на Haskell:

data Rose a = Leaf a | Rose [Rose a]

Вкратце, идея молнии заключается в том, чтобы представлять позицию в структуре данных по ее контексту. Контекст node в розовом дереве состоит из пути, по которому вы взяли дерево, чтобы добраться до родителя node, и путь, который вы взяли по списку братьев и сестер, чтобы достичь самого node.

data Path a = Top | Node (Path a) [Rose a] [Rose a]

data Pos a = Pos { focus :: Rose a, path :: Path a }

Это позволяет вам увеличить положение в дереве, не забывая, где вы были, идя right и down, а затем перестройте дерево, отступив left и уменьшив up.

right, down, left, up :: Pos a -> Maybe (Pos a)
right (Pos _ Top) = Nothing
right (Pos _ (Node _ _ [])) = Nothing
right (Pos t (Node p ls (r:rs))) = Just $ Pos r (Node p (t:ls) rs)

down (Pos (Leaf _) _) = Nothing
down (Pos (Rose []) _) = Nothing
down (Pos (Rose (t:ts)) p) = Just $ Pos t (Node p [] ts)

left (Pos _ Top) = Nothing
left (Pos _ (Node _ [] _)) = Nothing
left (Pos t (Node p (l:ls) rs) = Just $ Pos l (Node p ls (t:rs))

up (Pos _ Top) = Nothing
up (Pos t (Node p l r)) = Just $ Pos (Rose (l ++ t:r)) p

Посмотрите на определение up. Он принимает t, l и r - в настоящее время сосредоточенный node и его братья и сестры - и разбивает их вместе в один список детей. Он забывает о том, с какими node вы смотрели. Соответственно, down фокусирует вас на самом левом ребре текущего фокуса. Если вам нужно пойти up, а затем вернуться к ранее сфокусированному node, вам нужно пройти right по списку назад, где вы были, что является операцией O (n).

Идея Уэта оставить "шрамы" в дереве - это сделать его более удобным для возвращения к ранее сфокусированному ребенку. Он оснащает конструктор Rose своим фокусом, заменяя список детей на застежку-лист.

data SRose a =  -- for "scarred rose"
      SLeaf a
    | SEmpty  -- replaces (Rose [])
    | SRose [SRose a] (SRose a) [SRose a]

Типы Path и Pos остаются неизменными:

data SPath a = STop | SNode (SPath a) [SRose a] [SRose a]
data SPos a = SPos { sfocus :: Rose a, spath :: SPath a }

Теперь, когда вы идете up, а затем назад down, вы не забудете, о чем вы раньше смотрели.

up' (SPos _ STop) = Nothing
up' (SPos t (SNode p l r)) = Just $ SPos (SRose l t r) p

down' (SPos (SLeaf _) _) = Nothing
down' (SPos SEmpty _) = Nothing
down' (SPos (SRose l t r) p) = Just $ SPos t (SNode p l r)