1 Traversing Datastructures with Zippers
2 ======================================
4 This notebook is about using the “zipper” with joy datastructures. See
6 entry <https://en.wikipedia.org/wiki/Zipper_%28data_structure%29>`__ or
7 the original paper: `“FUNCTIONAL PEARL The Zipper” by Gérard
8 Huet <https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf>`__
10 Given a datastructure on the stack we can navigate through it, modify
11 it, and rebuild it using the “zipper” technique.
15 from notebook_preamble import J, V, define
20 In Joypy there aren’t any complex datastructures, just ints, floats,
21 strings, Symbols (strings that are names of functions) and sequences
22 (aka lists, aka quoted literals, aka aggregates, etc…), but we can build
23 `trees <https://en.wikipedia.org/wiki/Tree_%28data_structure%29>`__ out
28 J('[1 [2 [3 4 25 6] 7] 8]')
33 [1 [2 [3 4 25 6] 7] 8]
39 Zippers work by keeping track of the current item, the already-seen
40 items, and the yet-to-be seen items as you traverse a datastructure (the
41 datastructure used to keep track of these items is the zipper.)
43 In Joy we can do this with the following words:
47 z-down == [] swap uncons swap
48 z-up == swons swap shunt
49 z-right == [swons] cons dip uncons swap
50 z-left == swons [uncons swap] dip swap
52 Let’s use them to change 25 into 625. The first time a word is used I
53 show the trace so you can see how it works. If we were going to use
54 these a lot it would make sense to write Python versions for efficiency,
59 define('z-down == [] swap uncons swap')
60 define('z-up == swons swap shunt')
61 define('z-right == [swons] cons dip uncons swap')
62 define('z-left == swons [uncons swap] dip swap')
66 V('[1 [2 [3 4 25 6] 7] 8] z-down')
71 . [1 [2 [3 4 25 6] 7] 8] z-down
72 [1 [2 [3 4 25 6] 7] 8] . z-down
73 [1 [2 [3 4 25 6] 7] 8] . [] swap uncons swap
74 [1 [2 [3 4 25 6] 7] 8] [] . swap uncons swap
75 [] [1 [2 [3 4 25 6] 7] 8] . uncons swap
76 [] 1 [[2 [3 4 25 6] 7] 8] . swap
77 [] [[2 [3 4 25 6] 7] 8] 1 .
82 V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
87 . [] [[2 [3 4 25 6] 7] 8] 1 z-right
88 [] . [[2 [3 4 25 6] 7] 8] 1 z-right
89 [] [[2 [3 4 25 6] 7] 8] . 1 z-right
90 [] [[2 [3 4 25 6] 7] 8] 1 . z-right
91 [] [[2 [3 4 25 6] 7] 8] 1 . [swons] cons dip uncons swap
92 [] [[2 [3 4 25 6] 7] 8] 1 [swons] . cons dip uncons swap
93 [] [[2 [3 4 25 6] 7] 8] [1 swons] . dip uncons swap
94 [] . 1 swons [[2 [3 4 25 6] 7] 8] uncons swap
95 [] 1 . swons [[2 [3 4 25 6] 7] 8] uncons swap
96 [] 1 . swap cons [[2 [3 4 25 6] 7] 8] uncons swap
97 1 [] . cons [[2 [3 4 25 6] 7] 8] uncons swap
98 [1] . [[2 [3 4 25 6] 7] 8] uncons swap
99 [1] [[2 [3 4 25 6] 7] 8] . uncons swap
100 [1] [2 [3 4 25 6] 7] [8] . swap
101 [1] [8] [2 [3 4 25 6] 7] .
106 J('[1] [8] [2 [3 4 25 6] 7] z-down')
111 [1] [8] [] [[3 4 25 6] 7] 2
116 J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
121 [1] [8] [2] [7] [3 4 25 6]
126 J('[1] [8] [2] [7] [3 4 25 6] z-down')
131 [1] [8] [2] [7] [] [4 25 6] 3
136 J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
141 [1] [8] [2] [7] [3] [25 6] 4
146 J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
151 [1] [8] [2] [7] [4 3] [6] 25
156 J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
161 [1] [8] [2] [7] [4 3] [6] 625
166 V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
171 . [1] [8] [2] [7] [4 3] [6] 625 z-up
172 [1] . [8] [2] [7] [4 3] [6] 625 z-up
173 [1] [8] . [2] [7] [4 3] [6] 625 z-up
174 [1] [8] [2] . [7] [4 3] [6] 625 z-up
175 [1] [8] [2] [7] . [4 3] [6] 625 z-up
176 [1] [8] [2] [7] [4 3] . [6] 625 z-up
177 [1] [8] [2] [7] [4 3] [6] . 625 z-up
178 [1] [8] [2] [7] [4 3] [6] 625 . z-up
179 [1] [8] [2] [7] [4 3] [6] 625 . swons swap shunt
180 [1] [8] [2] [7] [4 3] [6] 625 . swap cons swap shunt
181 [1] [8] [2] [7] [4 3] 625 [6] . cons swap shunt
182 [1] [8] [2] [7] [4 3] [625 6] . swap shunt
183 [1] [8] [2] [7] [625 6] [4 3] . shunt
184 [1] [8] [2] [7] [3 4 625 6] .
189 J('[1] [8] [2] [7] [3 4 625 6] z-up')
194 [1] [8] [2 [3 4 625 6] 7]
199 J('[1] [8] [2 [3 4 625 6] 7] z-up')
204 [1 [2 [3 4 625 6] 7] 8]
207 ``dip`` and ``infra``
208 ---------------------
210 In Joy we have the ``dip`` and ``infra`` combinators which can “target”
211 or “address” any particular item in a Joy tree structure.
215 V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
220 . [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra
221 [1 [2 [3 4 25 6] 7] 8] . [[[[[[sqr] dipd] infra] dip] infra] dip] infra
222 [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] . infra
223 8 [2 [3 4 25 6] 7] 1 . [[[[[sqr] dipd] infra] dip] infra] dip [] swaack
224 8 [2 [3 4 25 6] 7] 1 [[[[[sqr] dipd] infra] dip] infra] . dip [] swaack
225 8 [2 [3 4 25 6] 7] . [[[[sqr] dipd] infra] dip] infra 1 [] swaack
226 8 [2 [3 4 25 6] 7] [[[[sqr] dipd] infra] dip] . infra 1 [] swaack
227 7 [3 4 25 6] 2 . [[[sqr] dipd] infra] dip [8] swaack 1 [] swaack
228 7 [3 4 25 6] 2 [[[sqr] dipd] infra] . dip [8] swaack 1 [] swaack
229 7 [3 4 25 6] . [[sqr] dipd] infra 2 [8] swaack 1 [] swaack
230 7 [3 4 25 6] [[sqr] dipd] . infra 2 [8] swaack 1 [] swaack
231 6 25 4 3 . [sqr] dipd [7] swaack 2 [8] swaack 1 [] swaack
232 6 25 4 3 [sqr] . dipd [7] swaack 2 [8] swaack 1 [] swaack
233 6 25 . sqr 4 3 [7] swaack 2 [8] swaack 1 [] swaack
234 6 25 . dup mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
235 6 25 25 . mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
236 6 625 . 4 3 [7] swaack 2 [8] swaack 1 [] swaack
237 6 625 4 . 3 [7] swaack 2 [8] swaack 1 [] swaack
238 6 625 4 3 . [7] swaack 2 [8] swaack 1 [] swaack
239 6 625 4 3 [7] . swaack 2 [8] swaack 1 [] swaack
240 7 [3 4 625 6] . 2 [8] swaack 1 [] swaack
241 7 [3 4 625 6] 2 . [8] swaack 1 [] swaack
242 7 [3 4 625 6] 2 [8] . swaack 1 [] swaack
243 8 [2 [3 4 625 6] 7] . 1 [] swaack
244 8 [2 [3 4 625 6] 7] 1 . [] swaack
245 8 [2 [3 4 625 6] 7] 1 [] . swaack
246 [1 [2 [3 4 625 6] 7] 8] .
249 If you read the trace carefully you’ll see that about half of it is the
250 ``dip`` and ``infra`` combinators de-quoting programs and “digging” into
251 the subject datastructure. Instead of maintaining temporary results on
252 the stack they are pushed into the pending expression (continuation).
253 When ``sqr`` has run the rest of the pending expression rebuilds the
259 Imagine a function ``Z`` that accepts a sequence of ``dip`` and
260 ``infra`` combinators, a quoted program ``[Q]``, and a datastructure to
261 work on. It would effectively execute the quoted program as if it had
262 been embedded in a nested series of quoted programs, e.g.:
266 [...] [Q] [dip dip infra dip infra dip infra] Z
267 -------------------------------------------------------------
268 [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
271 The ``Z`` function isn’t hard to make.
275 define('Z == [[] cons cons] step i')
277 Here it is in action in a simplified scenario.
289 1 [2 3 4] . [[] cons cons] step i
290 1 [2 3 4] [[] cons cons] . step i
291 1 2 [[] cons cons] . i [3 4] [[] cons cons] step i
292 1 2 . [] cons cons [3 4] [[] cons cons] step i
293 1 2 [] . cons cons [3 4] [[] cons cons] step i
294 1 [2] . cons [3 4] [[] cons cons] step i
295 [1 2] . [3 4] [[] cons cons] step i
296 [1 2] [3 4] . [[] cons cons] step i
297 [1 2] [3 4] [[] cons cons] . step i
298 [1 2] 3 [[] cons cons] . i [4] [[] cons cons] step i
299 [1 2] 3 . [] cons cons [4] [[] cons cons] step i
300 [1 2] 3 [] . cons cons [4] [[] cons cons] step i
301 [1 2] [3] . cons [4] [[] cons cons] step i
302 [[1 2] 3] . [4] [[] cons cons] step i
303 [[1 2] 3] [4] . [[] cons cons] step i
304 [[1 2] 3] [4] [[] cons cons] . step i
305 [[1 2] 3] 4 [[] cons cons] . i i
306 [[1 2] 3] 4 . [] cons cons i
307 [[1 2] 3] 4 [] . cons cons i
308 [[1 2] 3] [4] . cons i
315 And here it is doing the main thing.
319 J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
324 [1 [2 [3 4 625 6] 7] 8]
330 Because we are only using two combinators we could replace the list with
331 a string made from only two characters.
335 [...] [Q] 'ddididi' Zstr
336 -------------------------------------------------------------
337 [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
339 The string can be considered a name or address for an item in the
340 subject datastructure.
342 Determining the right “path” for an item in a tree.
343 ---------------------------------------------------
345 It’s easy to read off (in reverse) the right sequence of “d” and “i”
346 from the subject datastructure: