Skip to content

Instantly share code, notes, and snippets.

@saeidw
Created September 3, 2013 14:35
Show Gist options
  • Save saeidw/6424800 to your computer and use it in GitHub Desktop.
Save saeidw/6424800 to your computer and use it in GitHub Desktop.
A simple translation of the Zipper example from http://learnyouahaskell.com/zippers
# -----------------------------------------------------------------------------
# A tree is either an empty node, or a node with a left and right sub-tree
class Empty(object):
pass
class Node(object):
def __init__(self, value, left, right):
self.value = value
self.left = left
self.right = right
# -----------------------------------------------------------------------------
# A crumb is either a left crumb with a value and a right sub-tree,
# or a right crumb with a value and a left sub-tree.
# Crumbs represent the choice we make when traversing down a tree.
class LeftCrumb(object):
def __init__(self, value, right):
self.value = value
self.right = right
class RightCrumb(object):
def __init__(self, value, left):
self.value = value
self.left = left
# -----------------------------------------------------------------------------
# A tree zipper contains a tree, and a list of crumbs that we traversed to
# reach this (sub-)tree. If the list of crumbs is empty, we are at the root
# of the tree
class TreeZipper(object):
def __init__(self, tree, crumbs):
self.tree = tree
self.crumbs = crumbs
# -----------------------------------------------------------------------------
# To traverse left in a tree, we select the left sub-tree,
# and add a LeftCrumb to the list of crumbs
def goLeft(zipper):
focus = zipper.tree.left
crumb = LeftCrumb(zipper.tree.value, zipper.tree.right)
crumbs = [crumb] + zipper.crumbs
return TreeZipper(focus, crumbs)
# -----------------------------------------------------------------------------
# To traverse right in a tree, we select the right sub-tree,
# and add a RightCrumb to the list of crumbs
def goRight(zipper):
focus = zipper.tree.right
crumb = RightCrumb(zipper.tree.value, zipper.tree.left)
crumbs = [crumb] + zipper.crumbs
return TreeZipper(focus, crumbs)
# -----------------------------------------------------------------------------
# To traverse up in a tree, we reconstruct the parent node from the last
# crumb, and remove that crumb from the list.
def goUp(zipper):
c = zipper.crumbs[0]
crumbs = zipper.crumbs[1:]
if (isinstance(c, LeftCrumb)):
focus = Node(c.value, zipper.tree, c.right)
else:
focus = Node(c.value, c.left, zipper.tree)
return TreeZipper(focus, crumbs)
# -----------------------------------------------------------------------------
# Examples:
# A simple tree
t = Node(1,
Node(2, Empty(), Empty()),
Node(3, Empty(), Empty())
)
assert t.value == 1
assert t.left.value == 2
assert t.right.value == 3
# A zipper for our tree
z = TreeZipper(t, [])
assert z.tree.value == 1
leftZ = goLeft(z)
assert leftZ.tree.value == 2
rightZ = goRight(z)
assert rightZ.tree.value == 3
root1 = goUp(leftZ)
root2 = goUp(rightZ)
assert root1.tree.value == root2.tree.value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment