data-accessor 0.2.0.2 → 0.2.1
raw patch · 8 files changed
+190/−87 lines, 8 filesdep ~arraydep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: array, base, containers
API changes (from Hackage documentation)
+ Data.Accessor.Basic: fromWrapper :: (b -> a) -> (a -> b) -> T a b
+ Data.Accessor.Basic: result :: (Eq a) => a -> T (a -> r) r
Files
- RegExp +17/−0
- data-accessor.cabal +54/−18
- src-3/Data/Accessor/Private.hs +19/−0
- src-4/Data/Accessor/Private.hs +26/−0
- src/Data/Accessor.hs +8/−21
- src/Data/Accessor/Basic.hs +48/−22
- src/Data/Accessor/Example.hs +15/−25
- src/Data/Accessor/MonadState.hs +3/−1
+ RegExp view
@@ -0,0 +1,17 @@+Poor man's Template Haskell -+Here are Regular expression for replacement in NEdit:+Write data declaration like++data T =+ Cons {+ fieldA_ :: String,+ fieldB_ :: Int+ }++Copy the body of the 'data' declaration to where you want to define accessors.+Remove comments at the end of each field.+Use the first line as the pattern to find+and the second line for the pattern to replace by.++^\s*(\w+)_( *):: (.+?),?\n+\1 :: Accessor.T T \3\n\1 =\n Accessor.fromSetGet (\\x c -> c{\1_ = x}) \1_\n\n
data-accessor.cabal view
@@ -1,5 +1,5 @@ Name: data-accessor-Version: 0.2.0.2+Version: 0.2.1 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>, Luke Palmer <lrpalmer@gmail.com>@@ -7,9 +7,6 @@ Homepage: http://www.haskell.org/haskellwiki/Record_access Package-URL: http://code.haskell.org/data-accessor/ Category: Data--- Portability: Haskell98-Build-Type: Simple-Build-Depends: base>=1.0, array >=0.1 && <1, containers >=0.1 && <1, transformers >=0.0.1 && <0.2 Synopsis: Utilities for accessing and manipulating fields of records Description: In Haskell 98 the name of a record field@@ -42,25 +39,64 @@ > (('b',10),"hallo") . You can easily manipulate record fields in a 'Control.Monad.State.State' monad,- you can easily code Show instances that use the Accessor syntax+ you can easily code 'Show' instances that use the Accessor syntax and you can parse binary streams into records. See @Data.Accessor.Example@ for demonstration of all features. . It would be great if in revised Haskell versions the names of record fields are automatically 'Data.Accessor.Accessor's rather than plain @get@ functions.- The package @data-accessor-template@ provides Template Haskell functions+ For now, the package @data-accessor-template@ provides Template Haskell functions for automated generation of 'Data.Acesssor.Accessor's.-GHC-Options: -Wall+ .+ For similar packages see @lenses@ and @fclabel@.+ A related concept are editors+ <http://conal.net/blog/posts/semantic-editor-combinators/>.+ Editors only consist of a modify method+ (and @modify@ applied to a 'const' function is a @set@ function).+ This way, they can modify all function values of a function at once,+ whereas an accessor can only change a single function value,+ say, it can change @f 0 = 1@ to @f 0 = 2@.+ This way, editors can even change the type of a record or a function.+ An Arrow instance can be define for editors,+ but for accessors only a Category instance is possible ('(.)' method).+ The reason is the @arr@ method of the @Arrow@ class,+ that conflicts with the two-way nature (set and get) of accessors.+-- Portability: Haskell98+Cabal-Version: >=1.2 Tested-With: GHC==6.4.1 && ==6.8.2-Hs-Source-Dirs: src-Exposed-Modules:- Data.Accessor- Data.Accessor.Basic- Data.Accessor.Container- Data.Accessor.Show- Data.Accessor.Tuple- Data.Accessor.BinaryRead- Data.Accessor.MonadState-Other-Modules:- Data.Accessor.Example+Build-Type: Simple++Extra-Source-Files:+ RegExp+ src-3/Data/Accessor/Private.hs+ src-4/Data/Accessor/Private.hs++Flag category+ description: Check whether Arrow class is split into Arrow and Category.++Library+ Build-Depends:+ array >=0.1 && <0.3,+ containers >=0.1 && <0.3,+ transformers >=0.0.1 && <0.2+ If flag(category)+ Hs-Source-Dirs: src-4+ Build-Depends: base >= 4 && <6+ Else+ Hs-Source-Dirs: src-3+ Build-Depends: base >= 1 && <4++ GHC-Options: -Wall+ Hs-Source-Dirs: src+ Exposed-Modules:+ Data.Accessor+ Data.Accessor.Basic+ Data.Accessor.Container+ Data.Accessor.Show+ Data.Accessor.Tuple+ Data.Accessor.BinaryRead+ Data.Accessor.MonadState+ Other-Modules:+ Data.Accessor.Example+ Data.Accessor.Private
+ src-3/Data/Accessor/Private.hs view
@@ -0,0 +1,19 @@+module Data.Accessor.Private where++{- |+The access functions we propose, look very similar to those+needed for List.mapAccumL (but parameter order is swapped) and State monad.+They get the new value of the field and the record+and return the old value of the field and the record with the updated field.+-}+newtype T r a = Cons {decons :: a -> r -> (a, r)}++compose :: T a b -> T b c -> T a c+compose f g = Cons $ \ cNew aOld ->+ let (bOld, aNew) = decons f bNew aOld+ (cOld, bNew) = decons g cNew bOld+ in (cOld, aNew)++self :: T r r+self = Cons $ \ai ri -> (ri, ai)+
+ src-4/Data/Accessor/Private.hs view
@@ -0,0 +1,26 @@+module Data.Accessor.Private where++import qualified Control.Category as C+++{- |+The access functions we propose, look very similar to those+needed for List.mapAccumL (but parameter order is swapped) and State monad.+They get the new value of the field and the record+and return the old value of the field and the record with the updated field.+-}+newtype T r a = Cons {decons :: a -> r -> (a, r)}++compose :: T a b -> T b c -> T a c+compose f g = Cons $ \ cNew aOld ->+ let (bOld, aNew) = decons f bNew aOld+ (cOld, bNew) = decons g cNew bOld+ in (cOld, aNew)++self :: T r r+self = Cons $ \ai ri -> (ri, ai)+++instance C.Category T where+ id = self+ (.) = flip compose
src/Data/Accessor.hs view
@@ -75,6 +75,8 @@ infix 1 =:++{-# DEPRECATED (=:) "use (Data.Accessor.Monad.Trans.State.%=) from data-accessor-transformers package" #-} {- | An \"assignment operator\" for state monads. @@ -84,32 +86,17 @@ (=:) = putA -{--infix 1 %=, %:--{- |-Another infix variant of 'putA'-that provides more consistency with the infix operators for records-(without State monad).--}-(%=) :: Monad m => Accessor r a -> a -> StateT r m ()-(%=) = putA--{- |-Infix variant of 'modA'.--}-(%:) :: Monad m => Accessor r a -> (a -> a) -> StateT r m ()-(%:) = modA--}---- |A structural dereference function for state monads.+{-# DEPRECATED getA "Data.Accessor.Monad.Trans.State.get from data-accessor-transformers package" #-}+-- | A structural dereference function for state monads. getA :: Monad m => Accessor r a -> StateT r m a getA = State.get --- |A structural assignment function for state monads.+{-# DEPRECATED putA "Data.Accessor.Monad.Trans.State.set from data-accessor-transformers package" #-}+-- | A structural assignment function for state monads. putA :: Monad m => Accessor r a -> a -> StateT r m () putA = State.set --- |A structural modification function for state monads.+{-# DEPRECATED modA "Data.Accessor.Monad.Trans.State.modify from data-accessor-transformers package" #-}+-- | A structural modification function for state monads. modA :: Monad m => Accessor r a -> (a -> a) -> StateT r m () modA = State.modify
src/Data/Accessor/Basic.hs view
@@ -3,8 +3,8 @@ It should be imported with qualification. -} module Data.Accessor.Basic (- T, fromSetGet, fromLens,- self, null,+ T, fromSetGet, fromLens, fromWrapper,+ self, null, result, set, (^=), compose, get, (^.), modify, (^:),@@ -12,19 +12,13 @@ ($%), ) where +import qualified Data.Accessor.Private as A+import Data.Accessor.Private (T(..), ) import Prelude hiding (null) -- * Define and construct accessors -{- |-The access functions we propose, look very similar to those-needed for List.mapAccumL (but parameter order is swapped) and State monad.-They get the new value of the field and the record-and return the old value of the field and the record with the updated field.--}-newtype T r a = Cons {decons :: a -> r -> (a, r)}- fromSetGet :: (a -> r -> r) -> (r -> a) -> T r a fromSetGet setF getF = Cons $ \x r -> (getF r, setF x r)@@ -33,14 +27,43 @@ fromLens lens = Cons $ \ x r -> let (y,f) = lens r in (y, f x) +{- |+If an object is wrapped in a @newtype@,+you can generate an @Accessor@ to the unwrapped data+by providing a wrapper and an unwrapper function.+The set function is simpler in this case,+since no existing data must be kept.+Since the information content of the wrapped and unwrapped data is equivalent,+you can swap wrapper and unwrapper.+This way you can construct an @Accessor@+that treats a record field containing an unwrapped object+like a field containing a wrapped object. +> newtype A = A {unA :: Int}+>+> access :: Accessor.T A Int+> access = fromWrapper A unA+-}+fromWrapper :: (b -> a) -> (a -> b) -> T a b+fromWrapper wrap unwrap =+ fromSetGet (const . wrap) unwrap++{-+newtype A = A {unA :: Int}++access :: T A Int+access = fromWrapper A unA+-}++ -- Simple accessors {- | Access the record itself -} self :: T r r-self = fromSetGet const id+self = A.self+-- self = fromSetGet const id {- | Access a (non-existing) element of type @()@@@ -48,14 +71,16 @@ null :: T r () null = fromSetGet (flip const) (const ()) -{- {- |-Access the result of a function.-Cf. "http://conal.net/blog/posts/semantic-editor-combinators/"--}-result :: a -> T (a -> r) r-result = fromSetGet (flip const) (const ())+@result a@ accesses the value of a function for argument @a@.++Also see semantic editor combinators,+that allow to modify all function values of a function at once.+Cf. <http://conal.net/blog/posts/semantic-editor-combinators/> -}+result :: Eq a => a -> T (a -> r) r+result ai =+ fromSetGet (\r f a -> if a==ai then r else f a) ($ai) -- * Apply accessors, similar to State methods@@ -147,12 +172,13 @@ Speak \"stack\". -} (.>) :: T a b -> T b c -> T a c-(.>) f g = Cons $ \ cNew aOld ->- let (bOld, aNew) = decons f bNew aOld- (cOld, bNew) = decons g cNew bOld- in (cOld, aNew)+(.>) = A.compose +{-+This could be used for a Category instance of T.+-} + infixr 9 <. {- |@@ -161,4 +187,4 @@ > (<.) = flip (.>) -} (<.) :: T b c -> T a b -> T a c-(<.) = flip (.>)+(<.) = flip A.compose
src/Data/Accessor/Example.hs view
@@ -11,9 +11,6 @@ import qualified Data.Array as Array import qualified Data.Map as Map -import Data.Accessor.MonadState ((%=), (%:), )-import qualified Data.Accessor.MonadState as AState-import Control.Monad.Trans.State (State) import Data.Char (ord, toUpper, ) import Prelude hiding (init)@@ -29,28 +26,6 @@ Accessor.set first 'a' $ ('b',7) -state :: State (Char,Int) Int-state =- do AState.set first 'a'- AState.modify second succ- AState.get second--stateInfix :: State ((Char, Int), String) Int-stateInfix =- do str <- AState.get second- first.>first %= 'a'- first.>second %: succ- first.>first %= 'b'- second %= '!' : str- AState.get (first.>second)--stateLift :: State (Int, (Bool, Char)) ()-stateLift = do- first %= 42- AState.lift second $ do- first %: not- second %= 'q'- init :: (Char,Int) init = Accessor.compose@@ -115,6 +90,21 @@ null :: Char null = Accessor.null ^= () $ 'a' +{- |+Modify a value of the 'ord' function.+-}+result :: [Int]+result =+ let f = (Accessor.result 'a' ^= 65) ord+ in map f "abcABC"++{- |+Modify a value of a curried function.+-}+result2 :: [Int]+result2 =+ let f = (Accessor.result 0 ^: Accessor.result 0 ^= 1) div+ in map (uncurry f) [(4,2), (2,1), (0,0)] array :: Array.Array Int Char array =
src/Data/Accessor/MonadState.hs view
@@ -1,5 +1,7 @@ {- | Access helper functions in a State monad -}-module Data.Accessor.MonadState where+module Data.Accessor.MonadState+ {-# DEPRECATED "please use Data.Accessor.Monad.Trans.State from data-accessor-transformers" #-}+ where import qualified Data.Accessor.Basic as Accessor import qualified Control.Monad.Trans.State as State