Created
September 3, 2013 14:35
-
-
Save saeidw/6424800 to your computer and use it in GitHub Desktop.
A simple translation of the Zipper example from http://learnyouahaskell.com/zippers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ----------------------------------------------------------------------------- | |
# 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