pez 0.0.3 → 0.0.4
raw patch · 4 files changed
+145/−141 lines, 4 files
Files
- Data/Typeable/Zipper.hs +7/−3
- EXAMPLES/Examples.hs +0/−136
- EXAMPLES/Examples.lhs +136/−0
- pez.cabal +2/−2
Data/Typeable/Zipper.hs view
@@ -66,6 +66,7 @@ - ROADMAP: - Pink Elephant - Patiently Expectant+ - Pretty Extraordinary - Probably ?? - -}@@ -177,6 +178,7 @@ -- | return a SavedPath from n levels up to the current level+saveFromAbove :: (Typeable c, Typeable b) => Int -> Zipper a c -> Maybe (SavedPath b c) saveFromAbove n = fmap (S . zLenses) . mvUpSavingL n . flip ZL Nil . stack where mvUpSavingL :: (Typeable b', Typeable b)=> Int -> ZipperLenses a c b -> Maybe (ZipperLenses a c b')@@ -288,6 +290,8 @@ -- them in reversed order, forming a lens from top to bottom of a data -- structure: getReverseLensStack :: ZipperStack b a -> Thrist TypeableLens a b-getReverseLensStack = unflip . foldlThrist rev (Flipped Nil)- where rev (Flipped t) (H l _) = Flipped $ Cons (TL l) t-+getReverseLensStack = unflip . foldlThrist revLocal (Flipped Nil)+ --where rev (Flipped t) (H l _) = Flipped $ Cons (TL l) t+-- MAKING THIS GLOBAL SHOULD PLEASE GHC 7.0 WITHOUT EXTRA EXTENSIONS. SEE:+-- http://hackage.haskell.org/trac/ghc/blog/LetGeneralisationInGhc7+revLocal (Flipped t) (H l _) = Flipped $ Cons (TL l) t
− EXAMPLES/Examples.hs
@@ -1,136 +0,0 @@-> {-# LANGUAGE TemplateHaskell, DeriveDataTypeable, TypeOperators, ViewPatterns #-}--The first three extensions above are almost always required when using 'pez':- - TemplateHaskell for generating lenses via Data.Record.Label- - TypeOperators for infix (:->) from 'fclabels' package- - DeriveDataTypeable for deriving Typeable on user-defined types--We also use ViewPatterns which are useful for pattern matching on our zipper's-focus.--> module Main-> where-- Import the 'pez' library (which also brings in Data.Record.Label and-Data.Typeable:--> import Data.Typeable.Zipper-> import Control.Applicative--- ------------------------------------- EXAMPLE 1: - A binary tree- --------------------------------------- We define a simple binary search tree, deriving its Typeable instance.-Typeable "reify"s the type of some data, basically bringing some of the -type system into the world of data.- Further, we create accessor functions starting with an underdash. This-will let the 'fclabels' package generate lenses for our tree. See below.--> data Tree a = Node { _leftNode :: Tree a, -> _val :: a, -> _rightNode :: Tree a }-> | Nil -> deriving (Typeable,Show)- -- Now we use some templete haskell provided by 'fclabels' to generate our-lenses. We use these lenses to refer to children nodes we would like to move-to.- The code below will automatically create lenses named "leftNode", -"rightNode", and "val" at compile time. You can see their types in ghci.--> $(mkLabelsNoTypes [''Tree])---At this point we have everything we need to work with `Tree` in a Zipper! Let's -try it out on an example `Tree` that looks like...-- b- / \- a c--> tree = Node (Node Nil 'a' Nil) 'b' (Node Nil 'c' Nil)--Let's use our zipper to apply a clockwise rotation (a rebalancing procedure) -on the leftmost node, which in the case of the tree above would produce...-- a- \- b- \- c---> rotateLeftmost :: Tree Char -> Maybe (Tree Char)-> rotateLeftmost = fmap close . (doRotation =<<) . moveUp 1 . descend . zipper-> -- travel down the left side of the tree, until reaching a Nil branch:-> where descend z@(viewf-> Nil) = z-> descend z = descend $ moveTo leftNode z->-> -- use the Zipper1 type synonym for brevity when outer constructor-> -- is the same as the focus:-> doRotation :: Zipper1 (Tree Char) -> Maybe (Zipper1 (Tree Char))-> doRotation z1@(viewf->Node l1 a1 r1) = do-> -- navigate up one level in the zipper:-> z0 <- moveUp 1 $ setL focus Nil z1-> -- perform clockwise rotation:-> let (Node _ a0 r0) = viewf z0-> z0' = setL focus (Node l1 a1 $ Node r1 a0 r0) z0-> return z0'--- ------------------------------------- EXAMPLE 1b: - Monadic interface- -------------------------------------- The code above would be a little less clunky if we used a State monad.-Specifically, we will use the State / Maybe monad transformer, and see how-the code above looks:--... > type ZipperState a = StateT (Zipper1 (Tree Char)) Maybe a-...todo when we finish the monadic interface--- ------------------------------------- EXAMPLE 2- Mutually-recursive types- --------------------------------------Typeable allows us to define 'moveUp' on mutually-recursive data types, when we-wouldn't otherwise be able to make such a function type-check. It falls on the-module user to make sure that a 'moveUp' will land us at the type we were-expecting. Here is an example:--> newtype Timer = Timer { tickTocks :: Tick } deriving Show->-> data Tick = Tick { _tock :: Tock }-> | Claaaannnnggg deriving (Show, Typeable)->-> data Tock = Tock { _tick :: Tick } deriving (Show, Typeable)->-> timer = Timer $ Tick $ Tock $ Tick $ Tock $ Claaaannnnggg--Once again we will generate the labels for the types we will pass through with-our zipper:--> $(mkLabelsNoTypes [''Tick, ''Tock])---Let's make a function that shortens the timer by one tick-tock pair. We'll also-demonstrate some of the convenience operators for moving and setting the focus,-these may change or disappear if I decide they are a bad idea:--> shortenTimer :: Timer -> Maybe Timer-> shortenTimer = fmap (Timer . close) . shortenTick . zipper . tickTocks-> where shortenTick z@(viewf-> Claaaannnnggg) = -> z .- 2 ?> Claaaannnnggg-> shortenTick z = shortenTick (z .+ tock .+ tick)--The function above would have returned Nothing from 'moveUp' had the timer not -had at least one Tick-Tock pair, OR should we have arrived by moving up at a-type we were not expecting.
+ EXAMPLES/Examples.lhs view
@@ -0,0 +1,136 @@+> {-# LANGUAGE TemplateHaskell, DeriveDataTypeable, TypeOperators, ViewPatterns #-}++The first three extensions above are almost always required when using 'pez':+ - TemplateHaskell for generating lenses via Data.Record.Label+ - TypeOperators for infix (:->) from 'fclabels' package+ - DeriveDataTypeable for deriving Typeable on user-defined types++We also use ViewPatterns which are useful for pattern matching on our zipper's+focus.++> module Main+> where++ Import the 'pez' library (which also brings in Data.Record.Label and+Data.Typeable:++> import Data.Typeable.Zipper+> import Control.Applicative+++ ------------------------------------+ EXAMPLE 1: + A binary tree+ ------------------------------------+++ We define a simple binary search tree, deriving its Typeable instance.+Typeable "reify"s the type of some data, basically bringing some of the +type system into the world of data.+ Further, we create accessor functions starting with an underdash. This+will let the 'fclabels' package generate lenses for our tree. See below.++> data Tree a = Node { _leftNode :: Tree a, +> _val :: a, +> _rightNode :: Tree a }+> | Nil +> deriving (Typeable,Show)+ ++ Now we use some templete haskell provided by 'fclabels' to generate our+lenses. We use these lenses to refer to children nodes we would like to move+to.+ The code below will automatically create lenses named "leftNode", +"rightNode", and "val" at compile time. You can see their types in ghci.++> $(mkLabelsNoTypes [''Tree])+++At this point we have everything we need to work with `Tree` in a Zipper! Let's +try it out on an example `Tree` that looks like...++ b+ / \+ a c++> tree = Node (Node Nil 'a' Nil) 'b' (Node Nil 'c' Nil)++Let's use our zipper to apply a clockwise rotation (a rebalancing procedure) +on the leftmost node, which in the case of the tree above would produce...++ a+ \+ b+ \+ c+++> rotateLeftmost :: Tree Char -> Maybe (Tree Char)+> rotateLeftmost = fmap close . (doRotation =<<) . moveUp 1 . descend . zipper+> -- travel down the left side of the tree, until reaching a Nil branch:+> where descend z@(viewf-> Nil) = z+> descend z = descend $ moveTo leftNode z+>+> -- use the Zipper1 type synonym for brevity when outer constructor+> -- is the same as the focus:+> doRotation :: Zipper1 (Tree Char) -> Maybe (Zipper1 (Tree Char))+> doRotation z1@(viewf->Node l1 a1 r1) = do+> -- navigate up one level in the zipper:+> z0 <- moveUp 1 $ setL focus Nil z1+> -- perform clockwise rotation:+> let (Node _ a0 r0) = viewf z0+> z0' = setL focus (Node l1 a1 $ Node r1 a0 r0) z0+> return z0'+++ ------------------------------------+ EXAMPLE 1b: + Monadic interface+ ------------------------------------++ The code above would be a little less clunky if we used a State monad.+Specifically, we will use the State / Maybe monad transformer, and see how+the code above looks:++... > type ZipperState a = StateT (Zipper1 (Tree Char)) Maybe a+...todo when we finish the monadic interface+++ ------------------------------------+ EXAMPLE 2+ Mutually-recursive types+ ------------------------------------++Typeable allows us to define 'moveUp' on mutually-recursive data types, when we+wouldn't otherwise be able to make such a function type-check. It falls on the+module user to make sure that a 'moveUp' will land us at the type we were+expecting. Here is an example:++> newtype Timer = Timer { tickTocks :: Tick } deriving Show+>+> data Tick = Tick { _tock :: Tock }+> | Claaaannnnggg deriving (Show, Typeable)+>+> data Tock = Tock { _tick :: Tick } deriving (Show, Typeable)+>+> timer = Timer $ Tick $ Tock $ Tick $ Tock $ Claaaannnnggg++Once again we will generate the labels for the types we will pass through with+our zipper:++> $(mkLabelsNoTypes [''Tick, ''Tock])+++Let's make a function that shortens the timer by one tick-tock pair. We'll also+demonstrate some of the convenience operators for moving and setting the focus,+these may change or disappear if I decide they are a bad idea:++> shortenTimer :: Timer -> Maybe Timer+> shortenTimer = fmap (Timer . close) . shortenTick . zipper . tickTocks+> where shortenTick z@(viewf-> Claaaannnnggg) = +> z .- 2 ?> Claaaannnnggg+> shortenTick z = shortenTick (z .+ tock .+ tick)++The function above would have returned Nothing from 'moveUp' had the timer not +had at least one Tick-Tock pair, OR should we have arrived by moving up at a+type we were not expecting.
pez.cabal view
@@ -1,5 +1,5 @@ Name: pez-Version: 0.0.3+Version: 0.0.4 Synopsis: A Potentially-Excellent Zipper library Homepage: http://coder.bsimmons.name/blog/2011/04/pez-zipper-library-released/ @@ -71,7 +71,7 @@ -- Extra files to be distributed with the package, such as examples or -- a README.-Extra-source-files: EXAMPLES/Examples.hs, Tests.hs+Extra-source-files: EXAMPLES/Examples.lhs, Tests.hs -- Constraint on the version of Cabal needed to build this package. Cabal-version: >=1.2.3