zippers
DESCRIPTION
Zippers are a design pattern in functional programming languages, such as Haskell, which provides a focus point and methods for navigating around in a functional data structure. It turns out that for any algebraic data type with one parameter, the derivative of the type is a zipper for it.TRANSCRIPT
![Page 1: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/1.jpg)
Zippers
David Overton
1 August 2013
![Page 2: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/2.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 3: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/3.jpg)
Motivation
Navigating around in and updating mutable data structures is easy:• Keep a pointer to your current location in the data structure;• Update the pointer to move around the data structure;• Modify the data structure using destructive update via the pointer.
Example (C Array)
char my_array[1024];
char *p = my_array;
// Move right
p++;
// Move left
p--;
// Update focused element
*p = ’A’;
![Page 4: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/4.jpg)
Motivation
But what is the equivalent for an immutable data structure? I.e. how do we keep trackof a local focus point within a data structure? E.g. XML document tree, text editorbuffer, window manager stack (e.g. XMonad), AVL tree.
For a list we could use an integer to represent the element we are interested in:
type ListFocus a = (Int, [a])
but this requires traversing from the start of the list every time – an O(n) operation.For more complex types, this is even less practical.
Instead, we can use a data structure called a zipper.
![Page 5: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/5.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 6: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/6.jpg)
List Zipper
-- A list zipper is a pair consisting of the front
-- of the list (reversed) and the rear of the list.
type ListZipper a = ([a], [a])
-- Convert a list to a zipper.
-- Start at the front of the list.
fromList :: [a] → ListZipper a
fromList xs = ([], xs)
![Page 7: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/7.jpg)
List Zipper
-- Move about in the zipper.
right, left :: ListZipper a → ListZipper a
right (xs, y:ys) = (y:xs, ys)
left (x:xs, ys) = (xs, x:ys)
-- Modify the focused element.
modify :: (a → a) → ListZipper a → ListZipper a
modify f (xs, y:ys) = (xs, (f y):ys)
modify _ zs = zs
-- When we are finished, convert back to a list.
toList :: ListZipper a → [a]
toList ([], ys) = ys
toList zs = toList (left zs)
![Page 8: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/8.jpg)
*Main> let z = fromList [’a’, ’b’, ’c’]
*Main> z
("","abc")
a
ctx list
b
c
![Page 9: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/9.jpg)
*Main> right z
("a","bc")a
ctx list
b
c
![Page 10: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/10.jpg)
*Main> right $ right z
("ba","c")
a
ctx list
b c
![Page 11: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/11.jpg)
*Main> right $ right $ right z
("cba","")
a
ctx list
b
c
![Page 12: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/12.jpg)
List Zipper
Example (XMonad)
XMonad is a tiling window manager for X written in Haskell. The main data structurefor managing workspace and window focus uses nested list zippers.
type StackSet a = ListZipper (Workspace a)
type Workspace a = ListZipper (Window a)
This allows XMonad to keep track of the focused workspace in an ordered list ofworkspaces and also keep track of the focused window on each workspace.(This is a simplification of the actual types used. The zippers that XMonad uses allowwrapping when you reach the end of the window or workspace list.)
![Page 13: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/13.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 14: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/14.jpg)
Binary Tree
data Tree a
= Empty
| Node (Tree a) a (Tree a)
deriving Show
type Context a = Either (a, Tree a) (a, Tree a)
type TreeZipper a = ([Context a], Tree a)
fromTree :: Tree a → TreeZipper a
fromTree t = ([], t)
right, left, up :: TreeZipper a → TreeZipper a
right (ctx, Node l a r) = (Right (a, l) : ctx, r)
left (ctx, Node l a r) = (Left (a, r) : ctx, l)
![Page 15: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/15.jpg)
Binary Tree
up (Left (a, r) : ctx, l) = (ctx, Node l a r)
up (Right (a, l) : ctx, r) = (ctx, Node l a r)
modify :: (a → a) → TreeZipper a → TreeZipper a
modify f (ctx, Node l a r) = (ctx, Node l (f a) r)
modify f z = z
toTree :: TreeZipper a → Tree a
toTree ([], t) = t
toTree z = toTree (up z)
![Page 16: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/16.jpg)
*Main> let t = Node
(Node
(Node Empty ’d’ Empty)
’b’
(Node Empty ’e’ Empty))
’a’
(Node
(Node Empty ’f’ Empty)
’c’
(Node Empty ’g’ Empty))
*Main> fromTree t
a
cb
ed gf
ctx tree
![Page 17: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/17.jpg)
*Main> right $ fromTree t
( [Right (’a’,
Node
(Node Empty ’d’ Empty)
’b’
(Node Empty ’e’ Empty))],
Node
(Node Empty ’f’ Empty)
’c’
(Node Empty ’g’ Empty) )
Right
a c
b
ed
gf
ctx tree
![Page 18: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/18.jpg)
*Main> left $ right $ fromTree t
( [ Left (’c’, Node Empty ’g’ Empty),
Right (’a’,
Node
(Node Empty ’d’ Empty)
’b’
(Node Empty ’e’ Empty))],
Node Empty ’f’ Empty )
Right
Left
a
c
b
ed
g
f
ctx tree
![Page 19: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/19.jpg)
Tree Zippers
Example (XML)
• XPath navigation around an XML document is basically a zipper – you have acurrent context and methods to navigate to neighbouring nodes.
• One implementation of this in Haskell is the rose tree zipper from HXT.
data NTree a = NTree a [NTree a] -- A rose tree
data NTCrumb = NTC [NTree a] a [NTree a] -- "Breadcrumb" for context
-- The zipper itself
data NTZipper a = NTZ { ntree :: NTree a, context :: [NTCrumb a] }
-- And using it to represent XML
type XmlTree = NTree XNode
type XmlNavTree = NTZipper XNode
data XNode = XText String | XTag QName [XmlTree] | XAttr QName | · · ·
![Page 20: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/20.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 21: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/21.jpg)
Algebraic Data Types
Why are the types in languages such as Haskell sometimes referred to as AlgebraicData Types? One way to see the relationship to algebra is to convert the types toalgebraic expressions which represent the number of values that a type has.
data Void ⇔ 0 The empty typedata () = () ⇔ 1 The unit typedata Either a b = Left a | Right b ⇔ a + b A sum typetype Pair a b = (a, b) ⇔ a.b A product type
Technically, Haskell types form an algebraic structure called a semiring.
Some more examples:data Bool = False | True ⇔ 2data Maybe a = Nothing | Just a ⇔ 1 + atype Func a b = a -> b ⇔ ba An exponential typeInt ⇔ 232 or 264 (implementation dependent)
![Page 22: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/22.jpg)
Algebraic Laws
The usual algebraic laws (for semirings) hold, up to type “equivalence”:0 + a = a ⇔ Either Void a ∼= a
a + b = b + a ⇔ Either a b ∼= Either b a
0.a = 0 ⇔ (Void, a) ∼= Void
1.a = a ⇔ ((), a) ∼= a
a.b = b.a ⇔ (a, b) ∼= (b, a)
a.(b + c) = a.b + a.c ⇔ (a, Either b c) ∼= Either (a,b) (a,c)
(cb)a = cb.a ⇔ a -> b -> c ∼= (a, b) -> c
a2 = a.a ⇔ Bool -> a ∼= (a, a)
![Page 23: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/23.jpg)
Algebra of the List Type
data List a = Nil | Cons a (List a)
L(a) = 1 + a.L(a)= 1 + a.(1 + a.L(a))= 1 + a + a2(1 + a.L(a))= 1 + a + a2 + a3 + a4 + · · ·
So a list has either 0 elements or 1 element or 2 elements or . . . (which we alreadyknew!).Alternatively, solving for L(a):
L(a)− a.L(a) = 1(1− a).L(a) = 1
L(a) =1
1− a
It doesn’t seem to make much sense to do subtraction or division on types. But look
at the Taylor series expansion:1
1− a= 1 + a + a2 + a3 + a4 + · · ·
![Page 24: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/24.jpg)
Algebra of Tree Types
data Tree a = Empty | Node (Tree a) a (Tree a)
T (a) = 1 + a.T (a)2
a.T (a)2 − T (a) + 1 = 0
T (a) =1−√
1− 4.a
2.a
= 1 + a + 2a2 + 5a3 + 14a4 + · · ·
via the quadratic formula and Taylor series expansion. But now we are taking squareroots of types!
![Page 25: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/25.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 26: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/26.jpg)
One-Hole Contexts
DefinitionThe one-hole context of a parameterised type T (a) is the type of data structures youget if you remove one distinguished element of type a from a data structure of typeT (a) and somehow mark the hole where the element came from.
Example
type Triple a = (a, a, a)
The one-hole contexts are (�, a, a), (a, �, a), and (a, a, �). A type that couldrepresent this is
data TripleOhc a = Left a a | Mid a a | Right a a
![Page 27: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/27.jpg)
One-Hole Contexts
Look at the algebraic types:type Triple a = (a, a, a) ⇔ a3
type TripleOhc a = Left a a | Mid a a | Right a a ⇔ 3a2
Notice that
3a2 =d
daa3
In fact, this this relationship holds for any parameterised type T (a).
ObservationThe type of the one-hole context of any parameterized type T (a) is the derivative type
d
daT (a) or ∂aT (a)
![Page 28: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/28.jpg)
Zippers from One-Hole Contexts
ObservationFor any parameterized type T (a), the type a.∂aT (a) is a zipper for type T (a).
Example
The type
type TripleZipper a = (a, TripleOhc a)
is a zipper for the type Triple a.
TripleZipper(a) = a.3a2 = 3a3 = 3.Triple(a)
But what about some more interesting types . . . ?
![Page 29: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/29.jpg)
List Zipper
L(a) =1
1− a
∂aL(a) =1
(1− a)2= L(a)2
ZL(a) = a.∂aL(a) = a.L(a)2
type ListZipper a = (a, [a], [a])
This is slightly different from our original list zipper type ([a], [a]). Thedistinguished element is now pulled out of the second list and made explicit. This alsomeans that the zipper can’t be empty. However, this is still a list zipper and we derivedit using the differential calculus!
![Page 30: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/30.jpg)
Tree Zipper
T (a) = 1 + a.T (a)2
∂aT (a) = T (a)2 + 2a.T (a).∂aT (a)
∂aT (a) =T (a)2
1− 2a.T (a)
= T (a)2.L(2a.T (a))
ZT (a) = a.∂aT (a)
= a.T (a)2.L(2a.T (a))
type Context a = Either (a, Tree a) (a, Tree a)
type TreeZipper a = (a, Tree a, Tree a, [Context a])
![Page 31: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/31.jpg)
Table of Contents
1 Motivation
2 List Zipper
3 Tree Zippers
4 Algebraic Data Types
5 Type Differentiation
6 Conclusion
![Page 32: Zippers](https://reader033.vdocuments.us/reader033/viewer/2022052910/559b21241a28abc2738b4735/html5/thumbnails/32.jpg)
Conclusion
• Zippers are a useful way of navigating and manipulating mutable data structuresin real-world functional programs.
• Algebraic data types really are algebraic.
• Differentiation of types can lead to automatic derivation of zippers.
• Nobody really knows why this works yet — active research.