packages feed

fclabels 1.0 → 1.0.1

raw patch · 4 files changed

+65/−38 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Label: Lens :: Point ~> f a a -> Lens ~> f a
+ Data.Label: newtype Lens ~> f a

Files

fclabels.cabal view
@@ -1,5 +1,5 @@ Name:          fclabels-Version:       1.0+Version:       1.0.1 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@@ -19,11 +19,10 @@                .                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.+               > 1.0 -> 1.0.1+               >   - Some documentation cleanups.+               >   - Major performance improvements in setting and modifying+               >     values by inlining most label functions. Maintainer:    Sebastiaan Visser <code@fvisser.nl> License:       BSD3 License-File:  LICENCE
src/Data/Label.hs view
@@ -20,53 +20,55 @@  To illustrate this package, let's take the following two example datatypes. -> import Data.Label-> import Prelude hiding ((.), id)+>{-# LANGUAGE TemplateHaskell, TypeOperators #-}+>import Control.Category+>import Data.Label+>import Prelude hiding ((.), id) >-> data Person = Person->   { _name   :: String->   , _age    :: Int->   , _isMale :: Bool->   , _place  :: Place->   }+>data Person = Person+>  { _name   :: String+>  , _age    :: Int+>  , _isMale :: Bool+>  , _place  :: Place+>  } deriving Show >-> data Place = Place->   { _city->   , _country->   , _continent :: String->   }+>data Place = Place+>  { _city+>  , _country+>  , _continent :: String+>  } deriving Show  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])+>$(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")+>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+>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"+>moveToAmsterdam :: Person -> Person+>moveToAmsterdam = set (city . place) "Amsterdam"  And now: -> ghci> moveToAmsterdam jan-> Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe")+>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@@ -92,9 +94,11 @@ 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+>import Control.Applicative +>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@@ -107,14 +111,16 @@ 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"))+>moveToAmsterdamOverTwoYears :: Person -> Person+>moveToAmsterdamOverTwoYears = modify ageAndCity (\(a, _) -> (a+2, "Amsterdam")) -> ghci> moveToAmsterdamOverTwoYears jan-> Person "Jan" 73 True (Place "Amsterdam" "The Netherlands" "Europe")+>ghci> moveToAmsterdamOverTwoYears jan+>Person "Jan" 73 True (Place "Amsterdam" "The Netherlands" "Europe")  -} +, Lens (Lens)+ -- * Working with bijections and isomorphisms. --  -- | This package contains a bijection datatype that encodes bidirectional@@ -127,7 +133,7 @@ -- the following: --  -- > ageAsString :: Person :-> String--- > ageAsString :: Bij show read % age+-- > ageAsString = Bij show read `iso` age  , Bijection (..) , Iso (..)@@ -146,7 +152,7 @@ ) where -import Data.Label.Abstract (Bijection(..), Iso(..), for)+import Data.Label.Abstract (Bijection(..), Iso(..), for, Lens(..)) import Data.Label.Pure import Data.Label.Derive 
src/Data/Label/Abstract.hs view
@@ -12,6 +12,15 @@ import Control.Applicative import Control.Category +{-# INLINE _modify #-}+{-# INLINE lens    #-}+{-# INLINE get     #-}+{-# INLINE set     #-}+{-# INLINE modify  #-}+{-# INLINE bimap   #-}+{-# INLINE for     #-}+{-# INLINE liftBij #-}+ -- | Abstract Point datatype. The getter and setter functions work in some -- arrow. @@ -56,13 +65,18 @@   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,))+  {-# INLINE id #-}+  {-# INLINE (.) #-}  instance Arrow (~>) => Functor (Point (~>) f i) where   fmap f x = Point (arr f . _get x) (_set x)+  {-# INLINE fmap #-}  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))+  {-# INLINE pure #-}+  {-# INLINE (<*>) #-}  -- | Make a 'Point' diverge in two directions. @@ -83,6 +97,8 @@ instance Category (~>) => Category (Bijection (~>)) where   id = Bij id id   Bij a b . Bij c d = Bij (a . c) (d . b)+  {-# INLINE id #-}+  {-# INLINE (.) #-}  -- | Lifting 'Bijection's. @@ -100,9 +116,11 @@  instance Arrow (~>) => Iso (~>) (Lens (~>) f) where   iso bi = arr ((\a -> lens (fw bi . _get a) (_set a . first (bw bi))) . unLens)+  {-# INLINE iso #-}  -- | We can diverge 'Bijection's using an isomorphism.  instance Arrow (~>) => Iso (~>) (Bijection (~>) a) where   iso = arr . (.)+  {-# INLINE iso #-} 
src/Data/Label/Derive.hs view
@@ -74,10 +74,14 @@       return $        if signatures-       then [sign, body]-       else [body]+       then [sign, inline, body]+       else [inline, body]    where++    -- Generate an inline declaration for the label.+    inline = PragmaD (InlineP labelName (InlineSpec True True (Just (True, 0))))+      -- Build a single record label definition for labels that might fail.     deriveMaybeLabel = (sign, body)