packages feed

pez (empty) → 0.0.1

raw patch · 7 files changed

+698/−0 lines, 7 filesdep +basedep +fclabelsdep +thristsetup-changed

Dependencies added: base, fclabels, thrist

Files

+ Data/Record/Label/Prelude.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TypeOperators #-}+module Data.Record.Label.Prelude+    where++import Data.Record.Label+++-- First class labels pre-defined for the standard types from haskell's prelude++-- | [a]+lHead :: [a] :-> a+lHead = lens head (:)++lTail :: [a] :-> [a]+lTail = lens tail (\t-> (:t) . head)++-- | (a,b)+lFst :: (a,b) :-> a+lFst = lens fst (\a (_,b)-> (a,b))++lSnd :: (a,b) :-> b+lSnd = lens snd (\b (a,_)-> (a,b))
+ Data/Typeable/Zipper.hs view
@@ -0,0 +1,293 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, TypeOperators, TemplateHaskell, +GADTs, DeriveDataTypeable #-}+module Data.Typeable.Zipper (++    -- * Basic Zipper functionality+      Zipper() +    -- ** Creating and closing Zippers+    , zipper , close+    -- ** Moving around+    , ZPath(..) , moveUp+    -- ** Querying+    , focus , viewf , atTop       ++    -- * Advanced functionality+    -- ** Saving positions in a Zipper+    , SavedPath       +    , save        +    , saveFromAbove+    , savedLens   +    , closeSaving+    , moveUpSaving+    -- ** Recalling positions:+    , restore     ++    -- * Convenience operators, types, and exports+    , Zipper1+    -- ** Operators+    , (.+) , (.>) , (.-) , (?+) , (?>) , (?-)+    -- ** Export Typeable class and fclabels package+    , module Data.Record.Label+    , Data.Typeable.Typeable     +) where++{- + -   DESCRIPTION:+ -+ -   we use a Thrist to create a type-threaded stack of continuations+ -   allowing us to have a polymorphic history of where we've been.+ -   by using Typeable, we are able to "move up" by type casting in+ -   the Maybe monad. This means that the programmer has to know+ -   what type a move up will produce, or deal with unknowns.+ -+ -+ - TODO NOTES+ -+ -   - Include as part of package a module: Data.Record.Label.Prelude that+ -   exports labels for haskell builtin types+ -+ -   - Create a 'moveUntil' function, or something else to capture the ugly:+ -          descend z@(viewf -> Gong) = z+ -          descend z                 = descend $ moveTo tock z+ -    ...perhaps we can make something clever using property of pattern match+ -     failure in 'do' block?+ -+ -   - When the 'fclabels' package supports failure handling a.la the code on+ -   Github, then these functions will take advantage of that by returning+ -   Nothing when a lens is applied to an invalid constructor:+ -       * moveTo+ -       * restore+ -   + -   - consider instead of using section, use head form of parent with+ -   the child node set to undefined. Any performance difference?+ -+ -   - actually look at how this performs in terms of space/time+ -+ -   ROADMAP:+ -    Pink Elephant+ -    Patiently Expectant+ -    Probably ??+ -+ -}++ -- this is where the magic happens:+import Data.Record.Label+import Data.Typeable+import Data.Thrist++ -- for our accessors, which are a category:+import Control.Category         +import Prelude hiding ((.), id) -- take these from Control.Category+import Control.Applicative+++    -------------------------+    -- TYPES: the real heros+    ------------------------+++ -- We store our history in a type-threaded list of pairs of lenses and+ -- continuations (parent data-types with a "hole" where the child fits):+ --    Use GADT to enforce Typeable constraint+data HistPair b a where +    H :: (Typeable a, Typeable b)=> { hLens :: (a :-> b),+                                      hCont :: (b -> a) } -> HistPair b a++type ZipperStack b a = Thrist HistPair b a++data Zipper a b = Z { stack  :: ZipperStack b a,+                      _focus :: b                                  +                    } deriving (Typeable)+    ++-- | stores the path used to return to the same location in a data structure+-- as the one we just exited. You can also extract a lens from a SavedPath that+-- points to that location:+newtype SavedPath a b = S { savedLenses :: Thrist TypeableLens a b } +    deriving (Typeable, Category)++-- We need another GADT here to enforce the Typeable constraint within the+-- hidden types in our thrist of lenses above:+data TypeableLens a b where+    TL :: (Typeable a,Typeable b)=> {tLens :: (a :-> b)} -> TypeableLens a b++++-- TODO: TRY USING FUNDEPS ALA THE MONAD TRANSFORMER LIBRARIES FOR CLASS+-- CONSTRAINTS HERE:+--class (Typeable b, Typeable c) => ZPath p b c | p -> b, p -> c where+--+-- | Types of the ZPath class act as references to "paths" down through a datatype.+-- Currently lenses from 'fclabels' and SavedPath types are instances+class ZPath p where+    -- | Move down the structure to the label specified. Return Nothing if the+    -- label is not valid for the focus's constructor:+    moveTo :: (Typeable b, Typeable c) => p b c -> Zipper a b -> Zipper a c++++    ---------------------------+    -- Basic Zipper Functions:+    ---------------------------+++-- | a fclabel lens for setting, getting, and modifying the zipper's focus:+$(mkLabelsNoTypes [''Zipper])+++instance ZPath (:->) where+    moveTo = flip pivot . TL++instance ZPath SavedPath where+    moveTo = flip (foldlThrist pivot) . savedLenses  +++-- | Move up n levels as long as the type of the parent is what the programmer+-- is expecting and we aren't already at the top. Otherwise return Nothing.+moveUp :: (Typeable c, Typeable b)=> Int -> Zipper a c -> Maybe (Zipper a b)+moveUp 0  z                        = gcast z+moveUp n (Z (Cons (H _ f) stck) c) = moveUp (n-1) (Z stck $ f c)+moveUp _  _                        = Nothing  +++zipper :: a -> Zipper a a+zipper = Z Nil+++close :: Zipper a b -> a+close = snd . closeSaving++++    ------------------------------+    -- ADVANCED ZIPPER FUNCTIONS:+    ------------------------------++--- THIS FUNCTION GAVE ME THE MOST TROUBLE AND COULD PROBABLY BE SIMPLIFIED AND+--- 'moveUP' DEFINED IN TERMS OF IT, BUT FOR NOW I AM HAPPY WITH SOMETHING THAT+--- WORKS. ++-- | Move up a level as long as the type of the parent is what the programmer+-- is expecting and we aren't already at the top. Otherwise return Nothing.+moveUpSaving :: (Typeable c, Typeable b)=> Int -> Zipper a c -> Maybe (Zipper a b, SavedPath b c)+moveUpSaving n z = (,) <$> moveUp n z <*> saveFromAbove n z++data ZipperLenses a c b = ZL { zlStack :: ZipperStack b a,+                               zLenses :: Thrist TypeableLens b c }+++-- | return a SavedPath from n levels up to the current level+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')+        mvUpSavingL 0 z                           = gcast z+        mvUpSavingL n (ZL (Cons (H l _) stck) ls) = mvUpSavingL (n-1) (ZL stck $ Cons (TL l) ls)+        mvUpSavingL _ _                           = Nothing++++closeSaving :: Zipper a b -> (SavedPath a b, a)+closeSaving (Z stck b) = (S ls, a)+    where ls = getReverseLensStack stck+          a  = compStack (mapThrist hCont stck) b+++-- | Return a SavedPath type encapsulating the current location in the Zipper.+-- This lets you return to a location in your data type after closing the +-- Zipper.+save :: Zipper a b -> SavedPath a b+save = fst . closeSaving++-- | Extract a composed lens that points to the location we SavedPath. This lets +-- us modify, set or get a location that we visited with our Zipper after +-- closing the Zipper.+savedLens :: (Typeable a, Typeable b)=> SavedPath a b -> (a :-> b)+savedLens = compStack . mapThrist tLens . savedLenses+++-- | Return to a previously SavedPath location within a data-structure. +-- Saving and restoring lets us for example: find some location within our +-- structure using a Zipper, save the location, fmap over the entire structure,+-- and then return to where we were:+restore :: (ZPath p, Typeable a, Typeable b)=> p a b -> a -> Zipper a b+restore s = moveTo s  . zipper+++-- | returns True if Zipper is at the top level of the data structure:+atTop :: Zipper a b -> Bool+atTop = nullThrist . stack++{-+-- | Return our depth in the Zipper. if atTop z then level z == 0+level :: Zipper a b -> Int+level = foldlThrist (.) ...forgot how to do this :(+-}+----------------------------------------------------------------------------+++    ----------------+    -- CONVENIENCE+    ----------------++-- | a view function for a Zipper's focus. Defined simply as: `getL` focus+viewf :: Zipper a b -> b+viewf = getL focus++-- | a simple type synonym for a Zipper where the type at the focus is the+-- same as the type of the outer (unzippered) type. Cleans up type signatures+-- for simple recursive types:+type Zipper1 a = Zipper a a+++-- bind higher than <$>. Is this acceptable?:+infixl 5 .+, .>, .-, ?+, ?>, ?-++-- | 'moveTo' with arguments flipped. Operator plays on the idea of addition of+-- levels onto the focus.+(.+) :: (ZPath p, Typeable b, Typeable c)=> Zipper a b -> p b c -> Zipper a c+(.+) = flip moveTo++-- | 'moveUp' with arguments flipped. Operator syntax comes from the idea of+-- moving up as subtraction.+(.-) :: (Typeable c, Typeable b)=> Zipper a c -> Int -> Maybe (Zipper a b)+(.-) = flip moveUp++-- | setL focus, with arguments flipped+(.>) :: Zipper a b -> b -> Zipper a b+(.>) = flip (setL focus)++(?+) :: (ZPath p, Typeable b, Typeable c)=> Maybe (Zipper a b) -> p b c -> Maybe (Zipper a c)+(?+)= flip (fmap . moveTo)++(?-) :: (Typeable c, Typeable b)=> Maybe (Zipper a c) -> Int -> Maybe (Zipper a b)+mz ?- n = mz >>= moveUp n++(?>) :: Maybe (Zipper a b) -> b -> Maybe (Zipper a b)+(?>) = flip (fmap . setL focus)+++    ------------+    -- HELPERS+    ------------++ -- The core of our 'moveTo' function+pivot (Z t a') (TL l) = Z (Cons h t) b+    where h = H l (a' `missing` l)+          b = getL l a'+           --TODO: MAYBE GIVE THE GC SOME STRICTNESS HINTS HERE?:+          missing a l = flip (setL l) a+++ -- fold a thrist into a single category by composing the stack with (.)+ -- Here 'cat' will be either (->) or (:->):+compStack :: (Category cat)=> Thrist cat b a -> cat b a+compStack = foldrThrist (flip(.)) id+++ -- Takes the zipper stack and extracts each lens segment, and recomposes+ -- 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+
+ EXAMPLES/Examples.hs 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.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Brandon Simmons 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Brandon Simmons nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ Tests.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE DeriveDataTypeable, TemplateHaskell, ViewPatterns #-}+module Main+    where++import Test.QuickCheck+import Data.Typeable.Zipper+import Data.Record.Label.Prelude++{-+ - These tests are vital, since with all the dynamic magic we're using, a+ - function that compiles could very well not actually work+ -}++-- a linear, mutually recursive type:+data Tick = Tick { _tock :: Tock }+          | Gong +          deriving (Typeable, Eq, Show)++data Tock = LoudTock { _tick :: Tick }+          | SoftTock { _tick :: Tick }+          deriving (Typeable, Eq, Show)++newtype TickTock = TT { _tickTocks :: Tick }+                   deriving (Typeable, Eq, Show)++$(mkLabelsNoTypes [''TickTock, ''Tock, ''Tick])++instance Arbitrary TickTock where+    arbitrary = fmap TT arbTick where+        arbTick = do+            n <- choose (1,2) :: Gen Int+            case n of+                 1 -> fmap Tick arbTock+                 2 -> return Gong++        arbTock = do+            to <- elements [LoudTock, SoftTock]+            ti <- arbTick+            return $ to ti+++{-+-- a simple binary tree:+data Tree a = Branch (Tree a) (Tree a) +            | Leaf a+            deriving (Typeable, Eq)+-}++-- we also test on simple lists ++ -- Don't know the appropriate way to run batch job:+main = sequence_+        [ quickCheck prop_simple_creation+        , quickCheck prop_simple_recursive_movement+        , quickCheck prop_mutual_saving+        , quickCheck prop_simple_moveUp_past_top+        , quickCheck prop_moveUpSaving+        ]++prop_simple_creation :: [Char] -> Bool+prop_simple_creation a = +    let z = zipper a+        f = viewf z                           +        a' = close z                          +     in a == f && a == a'++prop_simple_recursive_movement i =+    let i' = abs i `mod` 50 :: Int+        l = replicate i' () +         -- test simple descending+        descend 0 z | null $ viewf z = maybe False atTop $  ascend i' z+                    | otherwise = False+        descend n z = descend (n-1) (moveTo lTail z)++         -- test ascending by two and one:+        ascend 0 z = return z+        ascend 1 z = moveUp 1 z+        ascend n z = moveUp 2 z >>= ascend (n-2)+     in descend i' $ zipper l+++prop_mutual_saving :: TickTock -> Bool+prop_mutual_saving tt = checkSaving $ descend $ moveTo tickTocks $ zipper tt+    where descend z@(viewf -> Gong) = z+          descend z = descendTock $ moveTo tock z+          descendTock = descend . moveTo tick+          checkSaving z = +              let (p,a) = closeSaving z+                  z' = restore p a+                  lns = savedLens p+               -- closed zipper is equal to original, +               in a == tt && +               -- restoring brings us back to the end+                  viewf z' == Gong && +               -- lens rebuilt from SavedPath is equivalent+                  getL lns tt == Gong &&+               -- moving to rebuilt lens and moving up gets us back to top:+                  (maybe False ((==tt) . viewf) $ +                      moveUp 1 $ moveTo lns $ zipper tt)++-- check moveUpSaving & Nothing returned from failed cast:+prop_moveUpSaving :: ((),((),(Int,Int))) -> Bool+prop_moveUpSaving = +   check . moveTo lSnd . moveTo lSnd . moveTo lSnd . zipper +       where check z = maybe False id $ do+                 (z', p') <- moveUpSaving 2 z+                 let n = viewf z +                     -- otherwise type is ambiguous:+                     typeofz' = z' :: Zipper ((),((),(Int,Int))) ((),(Int,Int))+                     n' = viewf $ moveTo p' z'+                 -- we successfully moved up and back down again?:+                 return $ n == n'++++-- test moveUp past top of Zipper, +prop_simple_moveUp_past_top :: [Int] -> Bool+prop_simple_moveUp_past_top = check . moveUp 2 . moveTo lTail . zipper where+    -- this sig required else type ambiguous:+    check :: Maybe (Zipper1 [Int]) -> Bool+    check = maybe True (const False)
+ pez.cabal view
@@ -0,0 +1,93 @@+Name:                pez+Version:             0.0.1+Synopsis:            A Potentially-Excellent Zipper library+Homepage:            http://coder.bsimmons.name/blog/2011/04/pez-zipper-library-released/+Description:+ PEZ is a generic zipper library. It uses lenses from the 'fclabels' package to+ reference a "location" to move to in the zipper. The zipper is restricted to+ types in the Typeable class, allowing the user to "move up" through complex data+ structures such as mutually-recursive types.+ .+ Both the Typeable class and fclabels lenses can be derived in GHC, making it+ easy for the programmer to use a zipper with a minimum of boilerplate.+ .+ First import the library, which brings in the Typeable and fclabels modules.+ You will also want to enable a few extensions:+ .+ > {-# LANGUAGE TemplateHaskell, DeriveDataTypeable, TypeOperators #-}+ > module Main where+ >+ > import Data.Typeable.Zipper+ .+ Create a datatype, deriving an instance of the Typeable class, and generate a+ lens using functions from fclabels:+ .+ > data Tree a = Node { _leftNode :: Tree a, + >                      _val      :: a, + >                      _rightNode :: Tree a }+ >             | Nil  + >             deriving (Typeable,Show)+ >+ > $(mkLabelsNoTypes [''Tree])+ .+ Now we can go crazy using Tree in a Zipper:+ .+ > treeBCD = Node (Node Nil 'b' Nil) 'c' (Node Nil 'd' Nil)+ > + > descendLeft :: Zipper1 (Tree a) -> Zipper1 (Tree a)+ > descendLeft z = case (viewf z) of+ >                      Nil -> z+ >                      _   -> descendLeft $ moveTo leftNode z+ >+ > insertLeftmost :: a -> Tree a -> Tree a+ > insertLeftmost x = close . setL focus x . descendLeft . zipper+ >+ > treeABCD = insertLeftmost 'a' treeBCD+ .+ Because of the flexibility of fclabels, this zipper library can be used to+ express moving about in reversible computations simply by defining such a lens,+ for instance:+ .+ > stringRep :: (Show b, Read b) => b :-> String+ > stringRep = lens show (const . read)+ .+ Please send any feature requests or bug reports along.++License:             BSD3+License-file:        LICENSE+Author:              Brandon Simmons+Maintainer:          brandon.m.simmons@gmail.com++-- A copyright notice.+Copyright:           Brandon Simmons, 2011++-- Stability of the pakcage (experimental, provisional, stable...)+Stability:           Experimental+Category:            Data+Build-type:          Simple++-- Extra files to be distributed with the package, such as examples or+-- a README.+Extra-source-files:  EXAMPLES/Examples.hs, Tests.hs++-- Constraint on the version of Cabal needed to build this package.+Cabal-version:       >=1.2.3+++Library+  -- Modules exported by the library.+  Exposed-modules:     Data.Typeable.Zipper+  +  -- Packages needed in order to build this package.+  Build-depends:       base >= 4 && < 5+                     , fclabels >= 0.11.1.1 && < 0.12+                     , thrist >= 0.2 && < 0.3++  Extensions:        GeneralizedNewtypeDeriving+                   , TypeOperators+                   , TemplateHaskell+                   , GADTs+                   , DeriveDataTypeable+  +  -- Modules not exported by this package.+  Other-modules:     Data.Record.Label.Prelude