Zippers in Haskell and Javascript (Part 1)
Sometimes we want to manipulate a location inside the data structure, rather than the data itself.
Suppose we have a data structure, a tree:
data Tree a = Branch (Tree a) (Tree a) | Leaf a
And a sample tree:
Branch (Branch (Leaf 1)
(Leaf 2))
(Branch (Leaf 3)
(Leaf 4))
In this case let’s manipulate the location of the subtree, Leaf 2
.
To know its location, we need to know its surroundings (context) and the place (focus)
tree = Branch (Branch (Leaf 1)
(Leaf 2)) -- Location of `Leaf 2`
(Branch (Leaf 3)
(Leaf 4))
-- Context surrounding `Leaf 2`
context = Branch (Branch (Leaf 1)
_
(Branch (Leaf 3)
(Leaf 4))
-- Focus of `Leaf 2`
focus = Leaf 2
As such we can define the location as a product of context
and the focus
:
type Loc a = (Tree a, Cxt a)
Context is in turn defined relative to the hole, where Context a
refers to the context of the parent, Tree a
refers to the other child of the parent.
data Context = Top | L (Context a) (Tree a) | R (Context a) (Tree a)
We can then define functions to manipulate locations in the tree:
left :: Loc a -> Loc a
left (Branch l r, c) = (l, L c r)
right :: Loc a -> Loc a
right (Branch l r, c) = (r, R c l)
top :: Tree a -> Loc a
top t = (t, Top)
up :: Loc a -> Loc a
up (t, L c r) = (Branch t r, c)
up (t, R c l) = (Branch l t, c)
upmost :: Loc a -> Loc a
upmost l@(t, Top) = l
upmost l = upmost (up l)
modify :: Loc a -> (Tree a -> Tree a) -> Loc a
modify (t, c) f = (f t, c)
Zippers in Haskell and Javascript (Part 2)
Further reading:
- Finding contexts in a structured way
- Further explanation about differentiating types
- In depth explanation to zippers
- Zippers and Comonads
References: