packages feed

fclabels 0.11.2 → 1.0

raw patch · 12 files changed

+643/−378 lines, 12 filesdep +transformersdep ~basedep ~mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

Dependency ranges changed: base, mtl

API changes (from Hackage documentation)

- Data.Record.Label: (%) :: Iso f => a :<->: b -> f a -> f b
- Data.Record.Label: (:<->:) :: (a -> b) -> (b -> a) -> :<->: a b
- Data.Record.Label: (=:) :: MonadState s m => s :-> b -> b -> m ()
- Data.Record.Label: Lens :: Point f a a -> :-> f a
- Data.Record.Label: Point :: (f -> o) -> (i -> f -> f) -> Point f i o
- Data.Record.Label: askM :: MonadReader r m => (r :-> b) -> m b
- Data.Record.Label: bw :: :<->: a b -> b -> a
- Data.Record.Label: class Iso f
- Data.Record.Label: data (:<->:) a b
- Data.Record.Label: data Point f i o
- Data.Record.Label: fmapL :: Applicative f => (a :-> b) -> f a :-> f b
- Data.Record.Label: for :: (i -> o) -> (f :-> o) -> Point f i o
- Data.Record.Label: fw :: :<->: a b -> a -> b
- Data.Record.Label: getL :: (f :-> a) -> f -> a
- Data.Record.Label: getM :: MonadState s m => s :-> b -> m b
- Data.Record.Label: lens :: (f -> a) -> (a -> f -> f) -> f :-> a
- Data.Record.Label: lmap :: Functor f => (a :<->: b) -> f a :<->: f b
- Data.Record.Label: localM :: MonadReader r m => (r :-> b) -> (b -> b) -> m a -> m a
- Data.Record.Label: mkLabels :: [Name] -> Q [Dec]
- Data.Record.Label: mkLabelsNoTypes :: [Name] -> Q [Dec]
- Data.Record.Label: modL :: (f :-> a) -> (a -> a) -> f -> f
- Data.Record.Label: modM :: MonadState s m => s :-> b -> (b -> b) -> m ()
- Data.Record.Label: newtype (:->) f a
- Data.Record.Label: setL :: (f :-> a) -> a -> f -> f
- Data.Record.Label: setM :: MonadState s m => s :-> b -> b -> m ()
- Data.Record.Label.Core: (%) :: Iso f => a :<->: b -> f a -> f b
- Data.Record.Label.Core: (:<->:) :: (a -> b) -> (b -> a) -> :<->: a b
- Data.Record.Label.Core: Lens :: Point f a a -> :-> f a
- Data.Record.Label.Core: Point :: (f -> o) -> (i -> f -> f) -> Point f i o
- Data.Record.Label.Core: _get :: Point f i o -> f -> o
- Data.Record.Label.Core: _mod :: Point f i o -> (o -> i) -> f -> f
- Data.Record.Label.Core: _set :: Point f i o -> i -> f -> f
- Data.Record.Label.Core: bw :: :<->: a b -> b -> a
- Data.Record.Label.Core: class Iso f
- Data.Record.Label.Core: data (:<->:) a b
- Data.Record.Label.Core: data Point f i o
- Data.Record.Label.Core: dimap :: (o' -> o) -> (i -> i') -> Point f i' o' -> Point f i o
- Data.Record.Label.Core: fmapL :: Applicative f => (a :-> b) -> f a :-> f b
- Data.Record.Label.Core: for :: (i -> o) -> (f :-> o) -> Point f i o
- Data.Record.Label.Core: fw :: :<->: a b -> a -> b
- Data.Record.Label.Core: getL :: (f :-> a) -> f -> a
- Data.Record.Label.Core: instance Applicative (Point f i)
- Data.Record.Label.Core: instance Category :->
- Data.Record.Label.Core: instance Category :<->:
- Data.Record.Label.Core: instance Functor (Point f i)
- Data.Record.Label.Core: instance Iso ((:->) i)
- Data.Record.Label.Core: instance Iso ((:<->:) i)
- Data.Record.Label.Core: lens :: (f -> a) -> (a -> f -> f) -> f :-> a
- Data.Record.Label.Core: lmap :: Functor f => (a :<->: b) -> f a :<->: f b
- Data.Record.Label.Core: modL :: (f :-> a) -> (a -> a) -> f -> f
- Data.Record.Label.Core: newtype (:->) f a
- Data.Record.Label.Core: setL :: (f :-> a) -> a -> f -> f
- Data.Record.Label.Core: unLens :: :-> f a -> Point f a a
- Data.Record.Label.Monadic: (=:) :: MonadState s m => s :-> b -> b -> m ()
- Data.Record.Label.Monadic: askM :: MonadReader r m => (r :-> b) -> m b
- Data.Record.Label.Monadic: getM :: MonadState s m => s :-> b -> m b
- Data.Record.Label.Monadic: localM :: MonadReader r m => (r :-> b) -> (b -> b) -> m a -> m a
- Data.Record.Label.Monadic: modM :: MonadState s m => s :-> b -> (b -> b) -> m ()
- Data.Record.Label.Monadic: setM :: MonadState s m => s :-> b -> b -> m ()
+ Data.Label: Bij :: a ~> b -> b ~> a -> Bijection ~> a b
+ Data.Label: bw :: Bijection ~> a b -> b ~> a
+ Data.Label: class Iso ~> f
+ Data.Label: data Bijection ~> a b
+ Data.Label: for :: Arrow ~> => (i ~> o) -> Lens ~> f o -> Point ~> f i o
+ Data.Label: fw :: Bijection ~> a b -> a ~> b
+ Data.Label: get :: (f :-> a) -> f -> a
+ Data.Label: iso :: Iso ~> f => Bijection ~> a b -> f a ~> f b
+ Data.Label: lens :: (f -> a) -> (a -> f -> f) -> f :-> a
+ Data.Label: mkLabels :: [Name] -> Q [Dec]
+ Data.Label: mkLabelsNoTypes :: [Name] -> Q [Dec]
+ Data.Label: modify :: (f :-> a) -> (a -> a) -> f -> f
+ Data.Label: set :: (f :-> a) -> a -> f -> f
+ Data.Label: type :-> f a = PureLens f a
+ Data.Label.Abstract: Bij :: a ~> b -> b ~> a -> Bijection ~> a b
+ Data.Label.Abstract: Lens :: Point ~> f a a -> Lens ~> f a
+ Data.Label.Abstract: Point :: f ~> o -> (i, f) ~> f -> Point ~> f i o
+ Data.Label.Abstract: _get :: Point ~> f i o -> f ~> o
+ Data.Label.Abstract: _modify :: ArrowApply ~> => Point ~> f i o -> (o ~> i, f) ~> f
+ Data.Label.Abstract: _set :: Point ~> f i o -> (i, f) ~> f
+ Data.Label.Abstract: bimap :: Arrow ~> => (o' ~> o) -> (i ~> i') -> Point ~> f i' o' -> Point ~> f i o
+ Data.Label.Abstract: bw :: Bijection ~> a b -> b ~> a
+ Data.Label.Abstract: class Iso ~> f
+ Data.Label.Abstract: data Bijection ~> a b
+ Data.Label.Abstract: data Point ~> f i o
+ Data.Label.Abstract: for :: Arrow ~> => (i ~> o) -> Lens ~> f o -> Point ~> f i o
+ Data.Label.Abstract: fw :: Bijection ~> a b -> a ~> b
+ Data.Label.Abstract: get :: Arrow ~> => Lens ~> f a -> f ~> a
+ Data.Label.Abstract: instance Arrow (~>) => Applicative (Point (~>) f i)
+ Data.Label.Abstract: instance Arrow (~>) => Functor (Point (~>) f i)
+ Data.Label.Abstract: instance Arrow (~>) => Iso (~>) (Bijection (~>) a)
+ Data.Label.Abstract: instance Arrow (~>) => Iso (~>) (Lens (~>) f)
+ Data.Label.Abstract: instance ArrowApply (~>) => Category (Lens (~>))
+ Data.Label.Abstract: instance Category (~>) => Category (Bijection (~>))
+ Data.Label.Abstract: iso :: Iso ~> f => Bijection ~> a b -> f a ~> f b
+ Data.Label.Abstract: lens :: (f ~> a) -> ((a, f) ~> f) -> Lens ~> f a
+ Data.Label.Abstract: liftBij :: Functor f => Bijection (->) a b -> Bijection (->) (f a) (f b)
+ Data.Label.Abstract: modify :: ArrowApply ~> => Lens ~> f o -> (o ~> o, f) ~> f
+ Data.Label.Abstract: newtype Lens ~> f a
+ Data.Label.Abstract: set :: Arrow ~> => Lens ~> f a -> (a, f) ~> f
+ Data.Label.Abstract: unLens :: Lens ~> f a -> Point ~> f a a
+ Data.Label.Maybe: embed :: Lens (->) f (Maybe a) -> f :~> a
+ Data.Label.Maybe: get :: (f :~> a) -> f -> Maybe a
+ Data.Label.Maybe: lens :: (f -> Maybe a) -> (a -> f -> Maybe f) -> f :~> a
+ Data.Label.Maybe: modify :: (f :~> a) -> (a -> a) -> f -> Maybe f
+ Data.Label.Maybe: set :: f :~> a -> a -> f -> Maybe f
+ Data.Label.Maybe: type :~> f a = MaybeLens f a
+ Data.Label.MaybeM: asks :: (MonadReader f m, MonadPlus m) => (f :~> a) -> m a
+ Data.Label.MaybeM: gets :: (MonadState f m, MonadPlus m) => (f :~> a) -> m a
+ Data.Label.Pure: get :: (f :-> a) -> f -> a
+ Data.Label.Pure: lens :: (f -> a) -> (a -> f -> f) -> f :-> a
+ Data.Label.Pure: modify :: (f :-> a) -> (a -> a) -> f -> f
+ Data.Label.Pure: set :: (f :-> a) -> a -> f -> f
+ Data.Label.Pure: type :-> f a = PureLens f a
+ Data.Label.PureM: (=:) :: MonadState s m => s :-> a -> a -> m ()
+ Data.Label.PureM: asks :: MonadReader r m => (r :-> a) -> m a
+ Data.Label.PureM: gets :: MonadState s m => s :-> a -> m a
+ Data.Label.PureM: local :: MonadReader r m => (r :-> b) -> (b -> b) -> m a -> m a
+ Data.Label.PureM: modify :: MonadState s m => s :-> a -> (a -> a) -> m ()
+ Data.Label.PureM: puts :: MonadState s m => s :-> a -> a -> m ()

Files

fclabels.cabal view
@@ -1,144 +1,57 @@-Name:            fclabels-Version:         0.11.2-Author:          Sebastiaan Visser, Erik Hesselink, Chris Eidhof, Sjoerd Visscher.-Synopsis:        First class accessor labels implemented as lenses.--Description:     First class labels that act as bidirectional record fields.-                 .-                 The labels are implemented as lenses and are fully composable-                 and can be used to get, set and modify parts of a datatype in-                 a consistent way. The lens datatype, conveniently called-                 `:->', is an instance of the `Category' type class: meaning it-                 has a proper identity and composition. The library has support-                 for automatically deriving labels from record selectors that-                 start with an underscore. Labels can be used in a purely-                 functional setting or be applied to mutable state in some-                 state monad.-                 .-                 To illustrate this package, let's take the following two example-                 datatypes (somehow Haddock removes the curly braces):-                 .-                 > data Person = Person {-                 >     _name   :: String-                 >   , _age    :: Int-                 >   , _isMale :: Bool-                 >   , _place  :: Place-                 >   }-                 .-                 > data Place = Place {-                 >     _city-                 >   , _country-                 >   , _continent :: String-                 >   }-                 .-                 Both are record datatypes with all record labels prefixed by-                 an underscore.  This underscore is an indication for our-                 Template Haskell code to derive lenses for these fields.-                 Deriving lenses can be done with this simple one-liner:-                 .-                 > $(mkLabels [''Person, ''Place])-                 .-                 These lenses can be used to get, set and modify the value and-                 are fully composable.-                 .-                 Now let's look at this example. This 71 year old fellow, called Jan,-                 is my neighbour and didn't mind using him as an example:-                 .-                 > jan :: Person-                 > jan = Person "Jan" 71 True (Place "Utrecht" "The Netherlands" "Europe")-                 .-                 When we want to be sure Jan is really as old as he claims we-                 can use the @getL@ function to get the age out as an integer:-                 .-                 > hisAge :: Int-                 > hisAge = getL age jan-                 .-                 Consider he now wants to move to Amsterdam: what better place-                 to spend your old days. Using composition we can change the-                 city value deep inside the structure:-                 .-                 > moveToAmsterdam :: Person -> Person-                 > moveToAmsterdam = setL (city . place) "Amsterdam"-                 .-                 > moveToAmsterdam jan ==-                 >  Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe")-                 .-                 Composition is done using the dot operator which is part of-                 the @Control.Category@ module. Make sure to import this module-                 and hide the default @(.)@, @id@ and @modL@ function from the-                 Prelude.-                 .-                 Now, because Jan is an old guy, moving to another city is not a-                 very easy task, this really takes a while. It will probably-                 take no less than two years before he will actually be-                 settled. To reflect this change it might be useful to have a-                 first class view on the @Person@ data type that only reveals-                 the age and city.  This can be done by using a neat-                 @Applicative@ functor instance:-                 .-                 > ageAndCity :: Person :-> (Int, String)-                 > ageAndCity = Lens $ (,) <$> fst `for` age <*> snd `for` (city . place)-                 .-                 Because the applicative type class on its own is not very-                 capable of expressing bidirectional relations, which we need-                 for our lenses, the actual instance is defined for an internal-                 helper structure called @Point@. Points are a bit more general-                 than lenses. As you can see above, the @Label@ constructor has-                 to be used to convert a @Point@ back into a @Label@. The @for@-                 function must be used to indicate which partial destructor to-                 use for which lens in the applicative composition.-                 .-                 Now that we have an appropriate age+city view on the @Person@-                 data type (which is itself a lens again), we can use the-                 @modL@ function to make Jan move to Amsterdam over exactly two-                 years:-                 .-                 > moveToAmsterdamOverTwoYears :: Person -> Person-                 > moveToAmsterdamOverTwoYears = modL ageAndCity (\(a, b) -> (a+2, "Amsterdam"))-                 .-                 > moveToAmsterdamOverTwoYears jan ==-                 >  Person "Jan" 73 True (Place "Amsterdam" "The Netherlands" "Europe")-                 .-                 This package also contains a lens data type that encodes-                 bidirectional functions. Just like lenses, lenses can be-                 composed with other lenses using the @Control.Category@ type-                 class. Lenses can be used to change the type of a lens. The-                 @Iso@ type class, which can be seen as a bidirectional-                 functor, can be used to apply lenses to lenses. For example,-                 when we want to treat the age of a person as a string we can-                 do the following:-                 .-                 > ageAsString :: Person :-> String-                 > ageAsString :: (show :<->: read) % age-                 .-                 A final note: this library might look cryptic at first sight, but give it a-                 try, it is not that hard.-                 .-                 .-                 > CHANGELOG-                 >   0.11.1.1 -> 0.11.2-                 >   - Relaxed template haskell dependency constraint-                 >     for GHC 7.2-                 >   - Removed redundant import warnings.--Maintainer:      Sebastiaan Visser <haskell@fvisser.nl>-License:         BSD3-License-File:    LICENCE-Category:        Data-Cabal-Version:   >= 1.6-Build-Type:      Simple+Name:          fclabels+Version:       1.0+Author:        Sebastiaan Visser, Erik Hesselink, Chris Eidhof, Sjoerd Visscher.+Synopsis:      First class accessor labels.+Description:   This package provides first class labels that can act as+               bidirectional record fields. The labels can be derived+               automatically using Template Haskell which means you don't have+               to write any boilerplate yourself. The labels are implemented as+               lenses and are fully composable. Labels can be used to /get/,+               /set/ and /modify/ parts of a datatype in a consistent way.+               .+               See "Data.Label" for an introductory explanation.+               .+               Internally lenses are not tied to Haskell functions directly,+               but are implemented as arrows. Arrows allow the lenses to be run+               in custom computational contexts. This approach allows us to+               make partial lenses that point to fields of multi-constructor+               datatypes in an elegant way.+               .+               See the "Data.Label.Maybe" module for the use of partial labels.+               .+               > 0.11.2 -> 1.0+               >   - Added abstract arrow based core module.+               >   - Allow both pure and failing labels to be derived.+               >   - Major API and documentation cleanup.+               >   - Renamed lots of exposed function names.+Maintainer:    Sebastiaan Visser <code@fvisser.nl>+License:       BSD3+License-File:  LICENCE+Category:      Data+Cabal-Version: >= 1.6+Build-Type:    Simple  Library   HS-Source-Dirs:  src-  Exposed-Modules: Data.Record.Label-                   Data.Record.Label.Core-                   Data.Record.Label.Monadic-  Other-Modules:   Data.Record.Label.TH-  Build-Depends:   base >= 3 && < 5-                 , template-haskell >= 2.2 && < 2.7-                 , mtl >= 1.1 && <= 2.1-  GHC-Options:     -Wall +  Other-Modules:+    Data.Label.Derive+  Exposed-Modules:+    Data.Label+    Data.Label.Abstract+    Data.Label.Maybe+    Data.Label.MaybeM+    Data.Label.Pure+    Data.Label.PureM++  GHC-Options: -Wall+  Build-Depends:+      base                       < 5+    , template-haskell >= 2.2 && < 2.7+    , mtl              >= 1.0 && < 2.2+    , transformers     >= 0.2 && < 0.3+ Source-Repository head-  Type:            git-  Location:        git://github.com/sebastiaanvisser/fclabels.git+  Type:     git+  Location: git://github.com/sebastiaanvisser/fclabels.git+
+ src/Data/Label.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE TypeOperators #-}+{- |+This package provides first class labels that can act as bidirectional record+fields. The labels can be derived automatically using Template Haskell which+means you don't have to write any boilerplate yourself. The labels are+implemented as lenses and are fully composable. Labels can be used to /get/,+/set/ and /modify/ parts of a datatype in a consistent way.+-}++module Data.Label+(++-- * Working with @fclabels@.++{- |+The lens datatype, conveniently called `:->', is an instance of the+"Control.Category" type class: meaning it has a proper identity and+composition. The library has support for automatically deriving labels from+record selectors that start with an underscore.++To illustrate this package, let's take the following two example datatypes.++> import Data.Label+> import Prelude hiding ((.), id)+>+> data Person = Person+>   { _name   :: String+>   , _age    :: Int+>   , _isMale :: Bool+>   , _place  :: Place+>   }+>+> data Place = Place+>   { _city+>   , _country+>   , _continent :: String+>   }++Both datatypes are record types with all the labels prefixed with an+underscore. This underscore is an indication for our Template Haskell code to+derive lenses for these fields. Deriving lenses can be done with this simple+one-liner:++> $(mkLabels [''Person, ''Place])++For all labels a lens will created.++Now let's look at this example. This 71 year old fellow, my neighbour called+Jan, didn't mind using him as an example:++> jan :: Person+> jan = Person "Jan" 71 True (Place "Utrecht" "The Netherlands" "Europe")++When we want to be sure Jan is really as old as he claims we can use the `get`+function to get the age out as an integer:++> hisAge :: Int+> hisAge = get age jan++Consider he now wants to move to Amsterdam: what better place to spend your old+days. Using composition we can change the city value deep inside the structure:++> moveToAmsterdam :: Person -> Person+> moveToAmsterdam = set (city . place) "Amsterdam"++And now:++> ghci> moveToAmsterdam jan+> Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe")++Composition is done using the @(`.`)@ operator which is part of the+"Control.Category" module. Make sure to import this module and hide the default+@(`.`)@, `id` function from the Haskell "Prelude".++-}++-- * Pure lenses.++  (:->)+, lens+, get+, set+, modify++-- * Views using @Applicative@.++{- |++Now, because Jan is an old guy, moving to another city is not a very easy task,+this really takes a while. It will probably take no less than two years before+he will actually be settled. To reflect this change it might be useful to have+a first class view on the `Person` datatype that only reveals the age and+city.  This can be done by using a neat `Applicative` functor instance:++> ageAndCity :: Person :-> (Int, String)+> ageAndCity = Lens $ (,) <$> fst `for` age <*> snd `for` city . place++Because the applicative type class on its own is not very capable of expressing+bidirectional relations, which we need for our lenses, the actual instance is+defined for an internal helper structure called `Point`. Points are a bit more+general than lenses. As you can see above, the `Label` constructor has to be+used to convert a `Point` back into a `Label`. The `for` function must be used+to indicate which partial destructor to use for which lens in the applicative+composition.++Now that we have an appropriate age+city view on the `Person` datatype (which+is itself a lens again), we can use the `modify` function to make Jan move to+Amsterdam over exactly two years:++> moveToAmsterdamOverTwoYears :: Person -> Person+> moveToAmsterdamOverTwoYears = modify ageAndCity (\(a, b) -> (a+2, "Amsterdam"))++> ghci> moveToAmsterdamOverTwoYears jan+> Person "Jan" 73 True (Place "Amsterdam" "The Netherlands" "Europe")++-}++-- * Working with bijections and isomorphisms.+-- +-- | This package contains a bijection datatype that encodes bidirectional+-- functions. Just like lenses, bijections can be composed using the+-- "Control.Category" type class. Bijections can be used to change the type of+-- a lens. The `Iso` type class, which can be seen as a bidirectional functor,+-- can be used to apply lenses to lenses.+-- +-- For example, when we want to treat the age of a person as a string we can do+-- the following:+-- +-- > ageAsString :: Person :-> String+-- > ageAsString :: Bij show read % age++, Bijection (..)+, Iso (..)+, for++-- * Derive labels using Template Haskell.+--+-- | We can either derive labels with or without type signatures. In the case+-- of multi-constructor datatypes some fields might not always be available and+-- the derived labels will be partial. Partial labels are provided with an+-- additional type context that forces them to be only usable using the+-- functions from "Data.Label.Maybe".++, mkLabels+, mkLabelsNoTypes+)+where++import Data.Label.Abstract (Bijection(..), Iso(..), for)+import Data.Label.Pure+import Data.Label.Derive+
+ src/Data/Label/Abstract.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE+    TypeOperators+  , Arrows+  , TupleSections+  , FlexibleInstances+  , MultiParamTypeClasses+  #-}+module Data.Label.Abstract where++import Control.Arrow+import Prelude hiding ((.), id)+import Control.Applicative+import Control.Category++-- | Abstract Point datatype. The getter and setter functions work in some+-- arrow.++data Point (~>) f i o = Point+  { _get :: f ~> o+  , _set :: (i, f) ~> f+  }++-- | Modification as a compositon of a getter and setter. Unfortunately,+-- `ArrowApply' is needed for this composition.++_modify :: ArrowApply (~>) => Point (~>) f i o -> (o ~> i, f) ~> f+_modify l = proc (m, f) -> do i <- m . _get l -<< f; _set l -< (i, f)++-- | Abstract Lens datatype. The getter and setter functions work in some+-- arrow. Arrows allow for effectful lenses, for example, lenses that might+-- fail or use state.++newtype Lens (~>) f a = Lens { unLens :: Point (~>) f a a }++-- | Create a lens out of a getter and setter.++lens :: (f ~> a) -> ((a, f) ~> f) -> Lens (~>) f a+lens g s = Lens (Point g s)++-- | Get the getter arrow from a lens.++get :: Arrow (~>) => Lens (~>) f a -> f ~> a+get = _get . unLens++-- | Get the setter arrow from a lens.++set :: Arrow (~>) => Lens (~>) f a -> (a, f) ~> f+set = _set . unLens++-- | Get the modifier arrow from a lens.++modify :: ArrowApply (~>) => Lens (~>) f o -> (o ~> o, f) ~> f+modify = _modify . unLens++instance ArrowApply (~>) => Category (Lens (~>)) where+  id = lens id (arr snd)+  Lens a . Lens b = lens (_get a . _get b) (_modify b . first (curryA (_set a)))+    where curryA f = arr (\i -> f . arr (i,))++instance Arrow (~>) => Functor (Point (~>) f i) where+  fmap f x = Point (arr f . _get x) (_set x)++instance Arrow (~>) => Applicative (Point (~>) f i) where+  pure a  = Point (arr (const a)) (arr snd)+  a <*> b = Point (arr app . (_get a &&& _get b)) (_set b . (arr fst &&& _set a))++-- | Make a 'Point' diverge in two directions.++bimap :: Arrow (~>) => (o' ~> o) -> (i ~> i') -> Point (~>) f i' o' -> Point (~>) f i o+bimap f g l = Point (f . _get l) (_set l . first g)++infix 8 `for`++for :: Arrow (~>) => (i ~> o) -> Lens (~>) f o -> Point (~>) f i o+for p = bimap id p . unLens++-- | The bijections datatype, an arrow that works in two directions. ++data Bijection (~>) a b = Bij { fw :: a ~> b, bw :: b ~> a }++-- | Bijections as categories.++instance Category (~>) => Category (Bijection (~>)) where+  id = Bij id id+  Bij a b . Bij c d = Bij (a . c) (d . b)++-- | Lifting 'Bijection's.++liftBij :: Functor f => Bijection (->) a b -> Bijection (->) (f a) (f b)+liftBij a = Bij (fmap (fw a)) (fmap (bw a))++-- | The isomorphism type class is like a `Functor' but works in two directions.++infixr 8 `iso`++class Iso (~>) f where+  iso :: Bijection (~>) a b -> f a ~> f b++-- | We can diverge 'Lens'es using an isomorphism.++instance Arrow (~>) => Iso (~>) (Lens (~>) f) where+  iso bi = arr ((\a -> lens (fw bi . _get a) (_set a . first (bw bi))) . unLens)++-- | We can diverge 'Bijection's using an isomorphism.++instance Arrow (~>) => Iso (~>) (Bijection (~>) a) where+  iso = arr . (.)+
+ src/Data/Label/Derive.hs view
@@ -0,0 +1,140 @@+{-# OPTIONS -fno-warn-orphans #-}+{-# LANGUAGE+    TemplateHaskell+  , OverloadedStrings+  , FlexibleInstances+  #-}+module Data.Label.Derive+( mkLabels+, mkLabelsNoTypes+) where++import Control.Arrow+import Control.Category+import Control.Monad+import Data.Char+import Data.Function (on)+import Data.Label.Abstract+import Data.List+import Data.Ord+import Data.String+import Language.Haskell.TH+import Language.Haskell.TH.Syntax+import Prelude hiding ((.), id)++-- Throw a fclabels specific error.++fclError :: String -> a+fclError err = error ("Data.Label.Derive: " ++ err)++-- | Derive lenses including type signatures for all the record selectors in a+-- datatype.++mkLabels :: [Name] -> Q [Dec]+mkLabels = liftM concat . mapM (derive1 True)++-- | Derive lenses without type signatures for all the record selectors in a+-- datatype.++mkLabelsNoTypes :: [Name] -> Q [Dec]+mkLabelsNoTypes = liftM concat . mapM (derive1 False)++-- Helpers to generate all labels.++derive1 :: Bool -> Name -> Q [Dec]+derive1 signatures datatype =+ do i <- reify datatype+    let -- Only process data and newtype declarations, filter out all+        -- constructors and the type variables.+        (tyname, cons, vars) =+          case i of+            TyConI (DataD    _ n vs cs _) -> (n, cs,  vs)+            TyConI (NewtypeD _ n vs c  _) -> (n, [c], vs)+            _                             -> fclError "Can only derive labels for datatypes and newtypes."++        -- We are only interested in lenses of record constructors.+        recordOnly = groupByCtor [ (f, n) | RecC n fs <- cons, f <- fs ]++    concat `liftM` mapM (derive signatures tyname vars (length cons)) recordOnly++    where groupByCtor = map (\xs -> (fst (head xs), map snd xs))+                      . groupBy ((==) `on` (fst3 . fst))+                      . sortBy (comparing (fst3 . fst))+                      where fst3 (a, _, _) = a++-- Generate the code for the labels.++derive :: Bool -> Name -> [TyVarBndr] -> Int -> (VarStrictType, [Name]) -> Q [Dec]+derive signatures tyname vars total ((field, _, fieldtyp), ctors) =++  do (sign, body) <-+       if length ctors == total+       then function derivePureLabel+       else function deriveMaybeLabel++     return $+       if signatures+       then [sign, body]+       else [body]++  where++    -- Build a single record label definition for labels that might fail.+    deriveMaybeLabel = (sign, body)+      where+        sign = forallT vars (return []) [t| (ArrowChoice (~>), ArrowZero (~>)) => Lens (~>) $(inputType) $(return fieldtyp) |]+        body = [| let c = zeroArrow ||| returnA in lens (c . $(getter)) (c . $(setter)) |]+          where+            getter    = [| arr (\    p  -> $(caseE [|p|] (cases (bodyG [|p|]      ) ++ wild))) |]+            setter    = [| arr (\(v, p) -> $(caseE [|p|] (cases (bodyS [|p|] [|v|]) ++ wild))) |]+            cases b   = map (\ctor -> match (recP ctor []) (normalB b) []) ctors+            wild      = [match wildP (normalB [| Left () |]) []]+            bodyS p v = [| Right $( record p fieldName v ) |]+            bodyG p   = [| Right $( fromString fieldName `appE` p ) |]++    -- Build a single record label definition for labels that cannot fail.+    derivePureLabel = (sign, body)+      where+        sign = forallT vars (return []) [t| Arrow (~>) => Lens (~>) $(inputType) $(return fieldtyp) |]+        body = [| lens $(getter) $(setter) |]+          where+            getter = [| arr $(fromString fieldName) |]+            setter = [| arr (\(v, p) -> $(record [| p |] fieldName [| v |])) |]++    -- Generate a name for the label. If the original selector starts with an+    -- underscore, remove it and make the next character lowercase. Otherwise,+    -- add 'l', and make the next character uppercase.+    fieldName = nameBase field+    labelName = mkName $+      case nameBase field of+        '_' : c : rest -> toLower c : rest+        f : rest       -> 'l' : toUpper f : rest+        n              -> fclError ("Cannot derive label for record selector with name: " ++ n)+++    -- Compute the type (including type variables of the record datatype.+    inputType = return $ foldr (flip AppT) (ConT tyname) (map tvToVarT (reverse vars))++    -- Convert a type variable binder to a regular type variable.+    tvToVarT (PlainTV tv) = VarT tv+    tvToVarT _            = fclError "No support for special-kinded type variables."++    -- Q style record updating.+    record rec fld val = val >>= \v -> recUpdE rec [return (mkName fld, v)]++    -- Build a function declaration with both a type signature and body.+    function (s, b) = liftM2 (,) +        (sigD labelName s)+        (funD labelName [ clause [] (normalB b) [] ])++-- IsString instances for TH types.++instance IsString Exp where+  fromString = VarE . mkName++instance IsString (Q Pat) where+  fromString = varP . mkName++instance IsString (Q Exp) where+  fromString = varE . mkName+
+ src/Data/Label/Maybe.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE TypeOperators, TupleSections #-}+module Data.Label.Maybe+( (:~>)+, lens+, get+, set+, modify+, embed+)+where++import Control.Arrow+import Control.Category+import Control.Monad.Identity+import Control.Monad.Trans.Maybe+import Data.Maybe+import Prelude hiding ((.), id)+import qualified Data.Label.Abstract as A++type MaybeLens f a = A.Lens (Kleisli (MaybeT Identity)) f a++-- | Lens type for situations in which the accessor functions can fail. This is+-- useful, for example, when accessing fields in datatypes with multiple+-- constructors.++type f :~> a = MaybeLens f a++run :: Kleisli (MaybeT Identity) f a -> f -> Maybe a+run l = runIdentity . runMaybeT . runKleisli l++-- | Create a lens that can fail from a getter and a setter that can themselves+-- potentially fail.++lens :: (f -> Maybe a) -> (a -> f -> Maybe f) -> f :~> a+lens g s = A.lens (kl g) (kl (uncurry s))+  where kl a = Kleisli (MaybeT . Identity . a)++-- | Getter for a lens that can fail. When the field to which the lens points+-- is not accessible the getter returns 'Nothing'.++get :: (f :~> a) -> f -> Maybe a+get l = run (A.get l)++-- | Setter for a lens that can fail. When the field to which the lens points+-- is not accessible this function returns 'Nothing'.++set :: f :~> a -> a -> f -> Maybe f+set l v = run (A.set l . arr (v,))++-- | Modifier for a lens that can fail. When the field to which the lens points+-- is not accessible this function returns 'Nothing'.++modify :: (f :~> a) -> (a -> a) -> f -> Maybe f+modify l m = run (A.modify l . arr (arr m,))++-- | Embed a pure lens that points to a `Maybe` field into+-- a lens that might fail.++embed :: A.Lens (->) f (Maybe a) -> f :~> a+embed l = lens (A.get l) (\a f -> Just (A.set l (Just a, f)))+
+ src/Data/Label/MaybeM.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE TypeOperators #-}+module Data.Label.MaybeM+(+-- * 'MonadState' lens operations.+  gets++-- * 'MonadReader' lens operations.+, asks+)+where++import Control.Monad+import Data.Label.Maybe ((:~>))+import qualified Control.Monad.Reader as M+import qualified Control.Monad.State  as M+import qualified Data.Label.Maybe     as L++-- | Get a value out of state, pointed to by the specified lens that might+-- fail.  When the lens getter fails this computation will fall back to+-- `mzero'.++gets :: (M.MonadState f m, MonadPlus m) => (f :~> a) -> m a+gets l = (L.get l `liftM` M.get) >>= (mzero `maybe` return)++-- | Fetch a value, pointed to by a lens that might fail, out of a reader+-- environment. When the lens getter fails this computation will fall back to+-- `mzero'.++asks :: (M.MonadReader f m, MonadPlus m) => (f :~> a) -> m a+asks l = (L.get l `liftM` M.ask) >>= (mzero `maybe` return)+
+ src/Data/Label/Pure.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE TypeOperators #-}+module Data.Label.Pure+( (:->)+, lens+, get+, set+, modify+)+where++import qualified Data.Label.Abstract as A++type PureLens f a = A.Lens (->) f a++-- | Pure lens type specialized for pure accessor functions.++type (f :-> a) = PureLens f a++-- | Create a pure lens from a getter and a setter.+--+-- We expect the following law to hold:+--+-- > get l (set l a f) == a+--+-- Or, equivalently:+--+-- > set l (get l f) f == f++lens :: (f -> a) -> (a -> f -> f) -> f :-> a+lens g s = A.lens g (uncurry s)++-- | Getter for a pure lens.++get :: (f :-> a) -> f -> a+get = A.get++-- | Setter for a pure lens.++set :: (f :-> a) -> a -> f -> f+set = curry . A.set++-- | Modifier for a pure lens.++modify :: (f :-> a) -> (a -> a) -> f -> f+modify = curry . A.modify+
+ src/Data/Label/PureM.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE TypeOperators  #-}+module Data.Label.PureM+(+-- * 'MonadState' lens operations.+  gets+, puts+, modify+, (=:)++-- * 'MonadReader' lens operations.+, asks+, local+)+where++import Data.Label.Pure ((:->))+import qualified Control.Monad.Reader as M+import qualified Control.Monad.State  as M+import qualified Data.Label.Pure      as L++-- | Get a value out of the state, pointed to by the specified lens.++gets :: M.MonadState s m => s :-> a -> m a+gets = M.gets . L.get++-- | Set a value somewhere in the state, pointed to by the specified lens.++puts :: M.MonadState s m => s :-> a -> a -> m ()+puts l = M.modify . L.set l++-- | Alias for `puts' that reads like an assignment.++infixr 7 =:+(=:) :: M.MonadState s m => s :-> a -> a -> m ()+(=:) = puts++-- | Modify a value with a function somewhere in the state, pointed to by the+-- specified lens.++modify :: M.MonadState s m => s :-> a -> (a -> a) -> m ()+modify l = M.modify . L.modify l++-- | Fetch a value pointed to by a lens out of a reader environment.++asks :: M.MonadReader r m => (r :-> a) -> m a+asks = M.asks . L.get++-- | Execute a computation in a modified environment. The lens is used to+-- point out the part to modify.++local :: M.MonadReader r m => (r :-> b) -> (b -> b) -> m a -> m a+local l f = M.local (L.modify l f)+
− src/Data/Record/Label.hs
@@ -1,28 +0,0 @@-module Data.Record.Label-(--- * Lens types.-  Point (Point)-, (:->) (Lens)-, lens-, getL, setL, modL--, fmapL---- * Bidirectional functor.-, (:<->:) (..)-, Iso (..)-, lmap-, for---- * Monadic lens operations.-, getM, setM, modM, (=:)-, askM, localM---- * Derive labels using Template Haskell.-, module Data.Record.Label.TH-)-where--import Data.Record.Label.Core-import Data.Record.Label.Monadic-import Data.Record.Label.TH
− src/Data/Record/Label/Core.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE TypeOperators #-}-module Data.Record.Label.Core where--import Prelude hiding ((.), id)-import Control.Applicative-import Control.Category--data Point f i o = Point-  { _get :: f -> o-  , _set :: i -> f -> f-  }--_mod :: Point f i o -> (o -> i) -> f -> f-_mod l f a = _set l (f (_get l a)) a--newtype (f :-> a) = Lens { unLens :: Point f a a }---- | Create a lens out of a getter and setter.--lens :: (f -> a) -> (a -> f -> f) -> f :-> a-lens g s = Lens (Point g s)---- | Get the getter function from a lens.--getL :: (f :-> a) -> f -> a-getL = _get . unLens---- | Get the setter function from a lens.--setL :: (f :-> a) -> a -> f -> f-setL = _set . unLens---- | Get the modifier function from a lens.--modL :: (f :-> a) -> (a -> a) -> f -> f-modL = _mod . unLens--instance Category (:->) where-  id = lens id const-  Lens a . Lens b = lens (_get a . _get b) (_mod b . _set a)--instance Functor (Point f i) where-  fmap f x = Point (f . _get x) (_set x)--instance Applicative (Point f i) where-  pure a = Point (const a) (const id)-  a <*> b = Point (_get a <*> _get b) (\r -> _set b r . _set a r)--fmapL :: Applicative f => (a :-> b) -> f a :-> f b-fmapL l = lens (fmap (getL l)) (\x f -> setL l <$> x <*> f)---- | This isomorphism type class is like a `Functor' but works in two directions.--class Iso f where-  (%) :: a :<->: b -> f a -> f b---- | The bijections datatype, a function that works in two directions. --infixr 7 :<->:-data a :<->: b = (:<->:) { fw :: a -> b, bw :: b -> a }---- | Constructor for bijections.--instance Category (:<->:) where-  id = id :<->: id-  (a :<->: b) . (c :<->: d) = a . c :<->: d . b--infixr 8 %--instance Iso ((:->) i) where-  l % Lens a = lens (fw l . _get a) (_set a . bw l)--instance Iso ((:<->:) i) where-  (%) = (.)--lmap :: Functor f => (a :<->: b) -> f a :<->: f b -lmap l = let a :<->: b = l in fmap a :<->: fmap b--dimap :: (o' -> o) -> (i -> i') -> Point f i' o' -> Point f i o-dimap f g l = Point (f . _get l) (_set l . g)---- | Combine a partial destructor with a lens into something easily used in the--- applicative instance for the hidden `Point' datatype. Internally uses the--- covariant in getter, contravariant in setter bi-functioral-map function.--- (Please refer to the example because this function is just not explainable--- on its own.)--for :: (i -> o) -> (f :-> o) -> Point f i o-for a b = dimap id a (unLens b)-
− src/Data/Record/Label/Monadic.hs
@@ -1,46 +0,0 @@-{-# LANGUAGE TypeOperators, TypeSynonymInstances, TemplateHaskell #-}-module Data.Record.Label.Monadic-(--- * Monadic lens operations.-  getM, setM, modM, (=:)-, askM, localM-)-where--import Control.Monad.State-import Control.Monad.Reader-import Data.Record.Label.Core---- | Get a value out of state pointed to by the specified lens.--getM :: MonadState s m => s :-> b -> m b-getM = gets . getL---- | Set a value somewhere in state pointed to by the specified lens.--setM :: MonadState s m => s :-> b -> b -> m ()-setM l = modify . setL l---- | Alias for `setM' that reads like an assignment.--infixr 7 =:-(=:) :: MonadState s m => s :-> b -> b -> m ()-(=:) = setM---- | Modify a value with a function somewhere in state pointed to by the--- specified lens.--modM :: MonadState s m => s :-> b -> (b -> b) -> m ()-modM l = modify . modL l---- | Fetch a value pointed to by a lens out of a reader environment.--askM :: MonadReader r m => (r :-> b) -> m b-askM = asks . getL---- | Execute a computation in a modified environment. The lens is used to--- point out the part to modify.--localM :: MonadReader r m => (r :-> b) -> (b -> b) -> m a -> m a-localM l f = local (modL l f)-
− src/Data/Record/Label/TH.hs
@@ -1,75 +0,0 @@-module Data.Record.Label.TH-( mkLabels-, mkLabelsNoTypes-) where--import Control.Monad-import Data.Char-import Data.List (nub)-import Language.Haskell.TH.Syntax---- | Derive lenses including type signatures for all the record selectors in a--- datatype.--mkLabels :: [Name] -> Q [Dec]-mkLabels = liftM concat . mapM (labels True)---- | Derive lenses without type signatures for all the record selectors in a--- datatype.--mkLabelsNoTypes :: [Name] -> Q [Dec]-mkLabelsNoTypes = liftM concat . mapM (labels False)---- Helpers to generate all labels.--labels :: Bool -> Name -> Q [Dec]-labels sigs n =- do i <- reify n-    let -- Only process data and newtype declarations, filter out all-        -- constructors and the type variables.-        (cs',vars) =-          case i of-            TyConI (DataD    _ _ vs cs _) -> (cs , vs)-            TyConI (NewtypeD _ _ vs c  _) -> ([c], vs)-            _                             -> ([], undefined)--        -- We are only interested in lenses of record constructors.-        ls' = [ l | RecC _ ls <- cs', l <- ls ]--    return (concatMap (label sigs n vars) (nub ls'))---- Helpers to generate a single labels.--label :: Bool -> Name -> [TyVarBndr] -> VarStrictType -> [Dec]-label withType typeName binders (field, _, typ) =-  if withType-    then [signature, body]-    else [body]--  where-    appTv w (PlainTV n) = AppT w (VarT n)-    appTv _ v           = error ("Kinded type variable not supported: " ++ show v)--    -- Generate a name for the lens. If the original selector starts with an _,-    -- remove it and make the next character lowercase. Otherwise, add 'l', and-    -- make the next character uppercase.-    name = mkName $-            case nameBase field of-              '_' : c : rest -> toLower c : rest-              f : rest       -> 'l' : toUpper f : rest-              _              -> error "Invalid name"--    -- The source type of a lens.-    source = foldl appTv (ConT typeName) binders--    -- Construct the lens type.-    signature = SigD name (ForallT binders [] (ConT (mkName ":->") `AppT` source `AppT` typ))--    -- Construct the lens body.-    body = -      let getter = VarE field -          setter = [VarP (mkName "b"), VarP (mkName "a")]-                     `LamE` RecUpdE (VarE (mkName "a")) [(field, VarE (mkName "b"))]-          lens   = VarE (mkName "lens") `AppE` getter `AppE` setter-      in FunD name [ Clause [] (NormalB lens) [] ]-