generic-accessors 0.5.1.0 → 0.6.0.0
raw patch · 7 files changed
+999/−420 lines, 7 filesdep +binarydep +cerealPVP ok
version bump matches the API change (PVP)
Dependencies added: binary, cereal
API changes (from Hackage documentation)
- Accessors: Data :: (String, String) -> [(String, AccessorTree a)] -> AccessorTree a
- Accessors: Field :: (Field a) -> AccessorTree a
- Accessors: FieldBool :: (Lens' a Bool) -> Field a
- Accessors: data AccessorTree a
- Accessors: data Field a
- Accessors: describeField :: Field a -> String
- Accessors: instance (Accessors.GLookupS f, Accessors.GLookupS g) => Accessors.GLookupS (f GHC.Generics.:*: g)
- Accessors: instance (Accessors.Lookup a, Accessors.Lookup b) => Accessors.Lookup (a, b)
- Accessors: instance (Accessors.Lookup a, Accessors.Lookup b, Accessors.Lookup c) => Accessors.Lookup (a, b, c)
- Accessors: instance (Accessors.Lookup a, Accessors.Lookup b, Accessors.Lookup c, Accessors.Lookup d) => Accessors.Lookup (a, b, c, d)
- Accessors: instance (GHC.Generics.Datatype d, GHC.Generics.Constructor c, Accessors.GLookupS a) => Accessors.GLookup (GHC.Generics.D1 d (GHC.Generics.C1 c a))
- Accessors: instance (GHC.Generics.Selector s, Accessors.GLookup a) => Accessors.GLookupS (GHC.Generics.S1 s a)
- Accessors: instance Accessors.GLookupS GHC.Generics.U1
- Accessors: instance Accessors.Lookup ()
- Accessors: instance Accessors.Lookup Foreign.C.Types.CChar
- Accessors: instance Accessors.Lookup Foreign.C.Types.CClock
- Accessors: instance Accessors.Lookup Foreign.C.Types.CDouble
- Accessors: instance Accessors.Lookup Foreign.C.Types.CFloat
- Accessors: instance Accessors.Lookup Foreign.C.Types.CInt
- Accessors: instance Accessors.Lookup Foreign.C.Types.CIntMax
- Accessors: instance Accessors.Lookup Foreign.C.Types.CIntPtr
- Accessors: instance Accessors.Lookup Foreign.C.Types.CLLong
- Accessors: instance Accessors.Lookup Foreign.C.Types.CLong
- Accessors: instance Accessors.Lookup Foreign.C.Types.CPtrdiff
- Accessors: instance Accessors.Lookup Foreign.C.Types.CSChar
- Accessors: instance Accessors.Lookup Foreign.C.Types.CSUSeconds
- Accessors: instance Accessors.Lookup Foreign.C.Types.CShort
- Accessors: instance Accessors.Lookup Foreign.C.Types.CSigAtomic
- Accessors: instance Accessors.Lookup Foreign.C.Types.CSize
- Accessors: instance Accessors.Lookup Foreign.C.Types.CTime
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUChar
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUInt
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUIntMax
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUIntPtr
- Accessors: instance Accessors.Lookup Foreign.C.Types.CULLong
- Accessors: instance Accessors.Lookup Foreign.C.Types.CULong
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUSeconds
- Accessors: instance Accessors.Lookup Foreign.C.Types.CUShort
- Accessors: instance Accessors.Lookup Foreign.C.Types.CWchar
- Accessors: instance Accessors.Lookup GHC.Base.String
- Accessors: instance Accessors.Lookup GHC.Int.Int16
- Accessors: instance Accessors.Lookup GHC.Int.Int32
- Accessors: instance Accessors.Lookup GHC.Int.Int64
- Accessors: instance Accessors.Lookup GHC.Int.Int8
- Accessors: instance Accessors.Lookup GHC.Types.Bool
- Accessors: instance Accessors.Lookup GHC.Types.Double
- Accessors: instance Accessors.Lookup GHC.Types.Float
- Accessors: instance Accessors.Lookup GHC.Types.Int
- Accessors: instance Accessors.Lookup GHC.Types.Word
- Accessors: instance Accessors.Lookup GHC.Word.Word16
- Accessors: instance Accessors.Lookup GHC.Word.Word32
- Accessors: instance Accessors.Lookup GHC.Word.Word64
- Accessors: instance Accessors.Lookup GHC.Word.Word8
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.Quaternion.Quaternion a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.V0.V0 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.V1.V1 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.V2.V2 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.V3.V3 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Linear.V4.V4 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (SpatialMathT.Rot f1 f2 a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (SpatialMathT.V3T f a)
- Accessors: instance Accessors.Lookup a => Accessors.Lookup (Types.Euler a)
- Accessors: instance Accessors.Lookup f => Accessors.GLookup (GHC.Generics.Rec0 f)
- Accessors: instance GHC.Show.Show (Accessors.AccessorTree a)
+ Accessors: GAConstructor :: String -> [(Maybe String, AccessorTree a)] -> GAConstructor a
+ Accessors: GAData :: String -> (GAConstructor a) -> GAData a
+ Accessors: GASimpleEnum :: [String] -> (a -> String) -> (a -> Int) -> (a -> String -> Either String a) -> (a -> Int -> Either String a) -> GASimpleEnum a
+ Accessors: GASum :: (GASimpleEnum a) -> GAConstructor a
+ Accessors: GATipField :: (GAField a) -> GATip a
+ Accessors: GATipSimpleEnum :: (GASimpleEnum a) -> GATip a
+ Accessors: [eConstructors] :: GASimpleEnum a -> [String]
+ Accessors: [eFromIndex] :: GASimpleEnum a -> a -> Int -> Either String a
+ Accessors: [eFromString] :: GASimpleEnum a -> a -> String -> Either String a
+ Accessors: [eToIndex] :: GASimpleEnum a -> a -> Int
+ Accessors: [eToString] :: GASimpleEnum a -> a -> String
+ Accessors: data GAConstructor a
+ Accessors: data GAData a
+ Accessors: data GAField a
+ Accessors: data GASimpleEnum a
+ Accessors: data GATip a
+ Accessors: describeGAField :: GAField a -> String
+ Accessors: type AccessorTree a = Either (GAField a) (GAData a)
+ Accessors.Dynamic: DConstructor :: String -> [(Maybe String, DTree)] -> DConstructor
+ Accessors.Dynamic: DData :: String -> DConstructor -> DData
+ Accessors.Dynamic: DDouble :: Double -> DField
+ Accessors.Dynamic: DFloat :: Float -> DField
+ Accessors.Dynamic: DInt :: Int -> DField
+ Accessors.Dynamic: DSimpleEnum :: [String] -> Int -> DSimpleEnum
+ Accessors.Dynamic: DSorry :: DField
+ Accessors.Dynamic: DString :: String -> DField
+ Accessors.Dynamic: DSum :: DSimpleEnum -> DConstructor
+ Accessors.Dynamic: data DConstructor
+ Accessors.Dynamic: data DData
+ Accessors.Dynamic: data DField
+ Accessors.Dynamic: data DSimpleEnum
+ Accessors.Dynamic: denumSetIndex :: DSimpleEnum -> Int -> Either String DSimpleEnum
+ Accessors.Dynamic: denumSetString :: DSimpleEnum -> String -> Either String DSimpleEnum
+ Accessors.Dynamic: denumToString :: DSimpleEnum -> Either String String
+ Accessors.Dynamic: denumToStringOrMsg :: DSimpleEnum -> String
+ Accessors.Dynamic: describeDField :: DField -> String
+ Accessors.Dynamic: instance Data.Binary.Class.Binary Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance Data.Binary.Class.Binary Accessors.Dynamic.DData
+ Accessors.Dynamic: instance Data.Binary.Class.Binary Accessors.Dynamic.DField
+ Accessors.Dynamic: instance Data.Binary.Class.Binary Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance Data.Data.Data Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance Data.Data.Data Accessors.Dynamic.DData
+ Accessors.Dynamic: instance Data.Data.Data Accessors.Dynamic.DField
+ Accessors.Dynamic: instance Data.Data.Data Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance Data.Serialize.Serialize Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance Data.Serialize.Serialize Accessors.Dynamic.DData
+ Accessors.Dynamic: instance Data.Serialize.Serialize Accessors.Dynamic.DField
+ Accessors.Dynamic: instance Data.Serialize.Serialize Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance GHC.Classes.Eq Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance GHC.Classes.Eq Accessors.Dynamic.DData
+ Accessors.Dynamic: instance GHC.Classes.Eq Accessors.Dynamic.DField
+ Accessors.Dynamic: instance GHC.Classes.Eq Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance GHC.Classes.Ord Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance GHC.Classes.Ord Accessors.Dynamic.DData
+ Accessors.Dynamic: instance GHC.Classes.Ord Accessors.Dynamic.DField
+ Accessors.Dynamic: instance GHC.Classes.Ord Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_0DConstructor
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_0DData
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_0DField
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_0DSimpleEnum
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_1DConstructor
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_1DField
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_2DField
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_3DField
+ Accessors.Dynamic: instance GHC.Generics.Constructor Accessors.Dynamic.C1_4DField
+ Accessors.Dynamic: instance GHC.Generics.Datatype Accessors.Dynamic.D1DConstructor
+ Accessors.Dynamic: instance GHC.Generics.Datatype Accessors.Dynamic.D1DData
+ Accessors.Dynamic: instance GHC.Generics.Datatype Accessors.Dynamic.D1DField
+ Accessors.Dynamic: instance GHC.Generics.Datatype Accessors.Dynamic.D1DSimpleEnum
+ Accessors.Dynamic: instance GHC.Generics.Generic Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance GHC.Generics.Generic Accessors.Dynamic.DData
+ Accessors.Dynamic: instance GHC.Generics.Generic Accessors.Dynamic.DField
+ Accessors.Dynamic: instance GHC.Generics.Generic Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: instance GHC.Show.Show Accessors.Dynamic.DConstructor
+ Accessors.Dynamic: instance GHC.Show.Show Accessors.Dynamic.DData
+ Accessors.Dynamic: instance GHC.Show.Show Accessors.Dynamic.DField
+ Accessors.Dynamic: instance GHC.Show.Show Accessors.Dynamic.DSimpleEnum
+ Accessors.Dynamic: sameDFieldType :: DField -> DField -> Bool
+ Accessors.Dynamic: toDData :: Lookup a => a -> DTree
+ Accessors.Dynamic: type DTree = Either DField DData
+ Accessors.Dynamic: updateLookupable :: Lookup a => a -> DTree -> Either String a
- Accessors: FieldDouble :: (Lens' a Double) -> Field a
+ Accessors: FieldDouble :: (Lens' a Double) -> GAField a
- Accessors: FieldFloat :: (Lens' a Float) -> Field a
+ Accessors: FieldFloat :: (Lens' a Float) -> GAField a
- Accessors: FieldInt :: (Lens' a Int) -> Field a
+ Accessors: FieldInt :: (Lens' a Int) -> GAField a
- Accessors: FieldSorry :: Field a
+ Accessors: FieldSorry :: GAField a
- Accessors: FieldString :: (Lens' a String) -> Field a
+ Accessors: FieldString :: (Lens' a String) -> GAField a
- Accessors: flatten :: AccessorTree a -> [(String, Field a)]
+ Accessors: flatten :: AccessorTree a -> [(String, GATip a)]
- Accessors: flatten' :: AccessorTree a -> [([String], Field a)]
+ Accessors: flatten' :: AccessorTree a -> [([Maybe String], GATip a)]
- Accessors: sameFieldType :: Field a -> Field b -> Bool
+ Accessors: sameFieldType :: GAField a -> GAField b -> Bool
Files
- CHANGELOG.md +6/−0
- generic-accessors.cabal +7/−2
- src/Accessors.hs +9/−397
- src/Accessors/Accessors.hs +385/−0
- src/Accessors/Dynamic.hs +221/−0
- src/Accessors/Instances.hs +219/−0
- tests/Tests.hs +152/−21
CHANGELOG.md view
@@ -1,3 +1,9 @@+0.6.0.0+---+* Split Datatype/Constructor/Field more cleanly.+* Add support for Enums with no fields.+* Add a dynamic representation for dynamic updating.+ 0.5.1.0 --- * Add tuple instances
generic-accessors.cabal view
@@ -1,5 +1,5 @@ name: generic-accessors-version: 0.5.1.0+version: 0.6.0.0 synopsis: stringly-named getters for generic data license: BSD3 license-file: LICENSE@@ -25,11 +25,16 @@ library hs-source-dirs: src default-language: Haskell2010- exposed-modules: Accessors+ exposed-modules: Accessors,+ Accessors.Dynamic+ other-modules: Accessors.Accessors,+ Accessors.Instances build-depends: base >= 4.6.0.0 && < 5 , linear , spatial-math >= 0.2.0 , lens+ , cereal+ , binary ghc-options: -O2 -Wall ghc-prof-options: -O2 -Wall -prof -fprof-auto -fprof-cafs -rtsopts
src/Accessors.hs view
@@ -1,17 +1,15 @@ {-# OPTIONS_GHC -Wall #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-} module Accessors ( Lookup(..)- , AccessorTree(..)- , Field(..)+ , AccessorTree+ , GAData(..)+ , GAConstructor(..)+ , GASimpleEnum(..)+ , GAField(..)+ , GATip(..) , accessors- , describeField+ , describeGAField , sameFieldType , flatten , flatten'@@ -19,391 +17,5 @@ , showFlat ) where -import GHC.Generics--import Control.Lens ( Lens', (^.) )-import Data.List ( intercalate )-import qualified Linear-import GHC.Word-import Data.Int-import Foreign.C.Types--import SpatialMath ( Euler )-import SpatialMathT ( V3T(..), Rot(..) )--showAccTree :: String -> AccessorTree a -> [String]-showAccTree spaces (Field _) = [spaces ++ "Field {}"]-showAccTree spaces (Data name trees) =- (spaces ++ "Data " ++ show name) :- concatMap (showChild (spaces ++ " ")) trees--showChild :: String -> (String, AccessorTree a) -> [String]-showChild spaces (name, tree) =- (spaces ++ name) : showAccTree (spaces ++ " ") tree--instance Show (AccessorTree a) where- show = unlines . showAccTree ""--data AccessorTree a = Data (String,String) [(String, AccessorTree a)]- | Field (Field a)--data Field a =- FieldBool (Lens' a Bool)- | FieldDouble (Lens' a Double)- | FieldFloat (Lens' a Float)- | FieldInt (Lens' a Int)- | FieldString (Lens' a String)- | FieldSorry -- ^ a field which is not yet supported---- | Return the type of field, such as "Bool", "Double", "String", etc.-describeField :: Field a -> String-describeField (FieldBool _) = "Bool"-describeField (FieldDouble _) = "Double"-describeField (FieldFloat _) = "Float"-describeField (FieldInt _) = "Int"-describeField (FieldString _) = "String"-describeField FieldSorry = "Sorry"---- | Returns True if the __type__ of fields is the same.-sameFieldType :: Field a -> Field b -> Bool-sameFieldType (FieldBool _) (FieldBool _) = True-sameFieldType (FieldDouble _) (FieldDouble _) = True-sameFieldType (FieldFloat _) (FieldFloat _) = True-sameFieldType (FieldInt _) (FieldInt _) = True-sameFieldType (FieldString _) (FieldString _) = True-sameFieldType FieldSorry FieldSorry = True-sameFieldType _ _ = False--accessors :: Lookup a => AccessorTree a-accessors = toAccessorTree id--showMsgs :: [String] -> String-showMsgs = intercalate "."--flatten :: AccessorTree a -> [(String, Field a)]-flatten = map f . flatten'- where- f (x,y) = (showMsgs x, y)--flatten' :: AccessorTree a -> [([String], Field a)]-flatten' = flattenChain []- where- flattenChain :: [String] -> AccessorTree a -> [([String], Field a)]- flattenChain msgs (Field lens) = [(reverse msgs, lens)]- flattenChain msgs (Data (_,_) trees) = concatMap f trees- where- f (name,tree) = flattenChain (name:msgs) tree---- | Things which you can make a tree of labeled getters for.--- You should derive this using GHC.Generics.-class Lookup a where- toAccessorTree :: Lens' b a -> AccessorTree b-- default toAccessorTree :: (Generic a, GLookup (Rep a))- => Lens' b a -> AccessorTree b- toAccessorTree lens0 = gtoAccessorTree (lens0 . repLens)- where- repLens :: Lens' a (Rep a p)- repLens f y = fmap to (f (from y))--class GLookup f where- gtoAccessorTree :: Lens' b (f a) -> AccessorTree b--class GLookupS f where- gtoAccessorTreeS :: Lens' b (f a)- -> [(String, AccessorTree b)]--instance Lookup f => GLookup (Rec0 f) where- gtoAccessorTree lens0 = toAccessorTree (lens0 . rec0Lens)- where- rec0Lens :: Lens' (Rec0 f a) f- rec0Lens f y = fmap K1 (f (unK1 y))--instance (Selector s, GLookup a) => GLookupS (S1 s a) where- gtoAccessorTreeS lens0 = [(selname, gtoAccessorTree (lens0 . m1Lens))]- where- m1Lens :: Lens' (S1 s f p) (f p)- m1Lens f y = fmap M1 (f (unM1 y))-- selname = case selName selError of- "" -> "()"- y -> y-- selError :: S1 s a p- selError = error $ "generic-accessors: selName should never access data"---instance GLookupS U1 where- gtoAccessorTreeS _ = []--instance (GLookupS f, GLookupS g) => GLookupS (f :*: g) where- gtoAccessorTreeS lens0 = tf ++ tg- where- tf = gtoAccessorTreeS (lens0 . leftLens)- tg = gtoAccessorTreeS (lens0 . rightLens)-- leftLens :: Lens' ((f :*: g) a) (f a)- leftLens f (x :*: y) = fmap (\x' -> x' :*: y ) (f x)- rightLens :: Lens' ((f :*: g) a) (g a)- rightLens f (x :*: y) = fmap (\y' -> x :*: y') (f y)--instance (Datatype d, Constructor c, GLookupS a)- => GLookup (D1 d (C1 c a)) where- gtoAccessorTree lens0 = Data (datatypeName datatypeError, conName conError) con- where- conError :: C1 c a p- conError = error $ "generic-accessors: conName should never access data"-- datatypeError :: D1 d (C1 c a) p- datatypeError = error $ "generic-accessors: datatypeName should never access data"-- con = gtoAccessorTreeS (lens0 . m1m1Lens)-- m1m1Lens :: Lens' (D1 d (C1 c f) p) (f p)- m1m1Lens f y = fmap (M1 . M1) (f (unM1 (unM1 y)))---- tuple instances-instance (Lookup a, Lookup b) => Lookup (a, b) where- toAccessorTree lens0 =- Data ("(,)", "(,)")- [ ("(x,_)", toAccessorTree (lens0 . lens1))- , ("(_,x)", toAccessorTree (lens0 . lens2))- ]- where- lens1 :: Lens' (a, b) a- lens1 f (x, y) = fmap (\x' -> (x', y)) (f x)- lens2 :: Lens' (a, b) b- lens2 f (x, y) = fmap (\y' -> (x, y')) (f y)--instance (Lookup a, Lookup b, Lookup c) => Lookup (a, b, c) where- toAccessorTree lens0 =- Data ("(,,)", "(,,)")- [ ("(x,_,_)", toAccessorTree (lens0 . lens1))- , ("(_,x,_)", toAccessorTree (lens0 . lens2))- , ("(_,_,x)", toAccessorTree (lens0 . lens3))- ]- where- lens1 :: Lens' (a, b, c) a- lens1 f (x, y, z) = fmap (\x' -> (x', y, z)) (f x)- lens2 :: Lens' (a, b, c) b- lens2 f (x, y, z) = fmap (\y' -> (x, y', z)) (f y)- lens3 :: Lens' (a, b, c) c- lens3 f (x, y, z) = fmap (\z' -> (x, y, z')) (f z)--instance (Lookup a, Lookup b, Lookup c, Lookup d) => Lookup (a, b, c, d) where- toAccessorTree lens0 =- Data ("(,,,)", "(,,,)")- [ ("(x,_,_,_)", toAccessorTree (lens0 . lens1))- , ("(_,x,_,_)", toAccessorTree (lens0 . lens2))- , ("(_,_,x,_)", toAccessorTree (lens0 . lens3))- , ("(_,_,_,x)", toAccessorTree (lens0 . lens4))- ]- where- lens1 :: Lens' (a, b, c, d) a- lens1 f (x, y, z, w) = fmap (\x' -> (x', y, z, w)) (f x)- lens2 :: Lens' (a, b, c, d) b- lens2 f (x, y, z, w) = fmap (\y' -> (x, y', z, w)) (f y)- lens3 :: Lens' (a, b, c, d) c- lens3 f (x, y, z, w) = fmap (\z' -> (x, y, z', w)) (f z)- lens4 :: Lens' (a, b, c, d) d- lens4 f (x, y, z, w) = fmap (\w' -> (x, y, z, w')) (f w)------ some instance from linear-instance Lookup a => Lookup (Linear.V0 a) where- toAccessorTree _ =- Data ("V0", "V0") []-instance Lookup a => Lookup (Linear.V1 a) where- toAccessorTree lens0 =- Data ("V1", "V1") [ ("x", toAccessorTree (lens0 . Linear._x))- ]--instance Lookup a => Lookup (Linear.V2 a) where- toAccessorTree lens0 =- Data ("V2", "V2") [ ("x", toAccessorTree (lens0 . Linear._x))- , ("y", toAccessorTree (lens0 . Linear._y))- ]--instance Lookup a => Lookup (Linear.V3 a) where- toAccessorTree lens0 =- Data ("V3", "V3") [ ("x", toAccessorTree (lens0 . Linear._x))- , ("y", toAccessorTree (lens0 . Linear._y))- , ("z", toAccessorTree (lens0 . Linear._z))- ]-instance Lookup a => Lookup (Linear.V4 a) where- toAccessorTree lens0 =- Data ("V4", "V4") [ ("x", toAccessorTree (lens0 . Linear._x))- , ("y", toAccessorTree (lens0 . Linear._y))- , ("z", toAccessorTree (lens0 . Linear._z))- , ("w", toAccessorTree (lens0 . Linear._w))- ]-instance Lookup a => Lookup (Linear.Quaternion a) where- toAccessorTree lens0 =- Data ("Quaternion", "Quaternion")- [ ("q0", toAccessorTree (lens0 . Linear._e))- , ("q1", toAccessorTree (lens0 . Linear._i))- , ("q2", toAccessorTree (lens0 . Linear._j))- , ("q3", toAccessorTree (lens0 . Linear._k))- ]---- basic types-instance Lookup () where -- hack to get dummy tree- toAccessorTree _ = Field FieldSorry-instance Lookup Int where- toAccessorTree lens = Field (FieldInt lens)-instance Lookup Float where- toAccessorTree lens = Field (FieldFloat lens)-instance Lookup Double where- toAccessorTree lens = Field (FieldDouble lens)-instance Lookup Bool where- toAccessorTree lens = Field (FieldBool lens)-instance Lookup String where- toAccessorTree lens = Field (FieldString lens)---- Word types-instance Lookup Word where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Word8 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Word16 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Word32 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Word64 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))---- Int types-instance Lookup Int8 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Int16 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Int32 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup Int64 where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))---- C types--- todo(greg): some of these have inappropriate fields-instance Lookup CChar where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CSChar where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CUChar where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CShort where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CUShort where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CInt where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CUInt where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CLong where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CULong where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CPtrdiff where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CSize where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CWchar where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CSigAtomic where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CLLong where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CULLong where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CIntPtr where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CUIntPtr where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CIntMax where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CUIntMax where- toAccessorTree lens0 = Field (FieldInt (lens0 . integralLens))-instance Lookup CClock where- toAccessorTree lens0 = Field (FieldInt (lens0 . clockLens))- where- clockLens f (CClock x) = fmap (CClock . fromIntegral) (f (fromIntegral x))-instance Lookup CTime where- toAccessorTree lens0 = Field (FieldInt (lens0 . timeLens))- where- timeLens f (CTime x) = fmap (CTime . fromIntegral) (f (fromIntegral x))-instance Lookup CUSeconds where- toAccessorTree lens0 = Field (FieldInt (lens0 . usecondsLens))- where- usecondsLens f (CUSeconds x) = fmap (CUSeconds . fromIntegral) (f (fromIntegral x))-instance Lookup CSUSeconds where- toAccessorTree lens0 = Field (FieldInt (lens0 . susecondsLens))- where- susecondsLens f (CSUSeconds x) = fmap (CSUSeconds . fromIntegral) (f (fromIntegral x))-instance Lookup CFloat where- toAccessorTree lens0 = Field (FieldDouble (lens0 . realFracLens))-instance Lookup CDouble where- toAccessorTree lens0 = Field (FieldDouble (lens0 . realFracLens))--{-# INLINE integralLens #-}-integralLens :: Integral a => Lens' a Int-integralLens f x = fmap fromIntegral (f (fromIntegral x))--{-# INLINE realFracLens #-}-realFracLens :: (Fractional a, Real a) => Lens' a Double-realFracLens f x = fmap realToFrac (f (realToFrac x))---- other types-instance Lookup a => Lookup (Rot f1 f2 a) where- toAccessorTree lens0 = toAccessorTree (lens0 . (\f x -> fmap Rot (f (unR x))))-instance Lookup a => Lookup (V3T f a) where- toAccessorTree lens0 = toAccessorTree (lens0 . (\f x -> fmap V3T (f (unV x))))-instance Lookup a => Lookup (Euler a)--showAccTrees :: (Double -> String) -> a -> [(String, AccessorTree a)] -> String -> [String]-showAccTrees show' x trees spaces = concat cs ++ [spaces ++ "}"]- where- cs = zipWith (showRecordField show' x spaces) trees ("{ " : repeat ", ")--showVal :: Field a -> (Double -> String) -> a -> String-showVal (FieldBool lens) _ x = show (x ^. lens)-showVal (FieldInt lens) _ x = show (x ^. lens)-showVal (FieldDouble lens) show' x = show' (x ^. lens)-showVal (FieldFloat lens) show' x = show' (realToFrac (x ^. lens))-showVal (FieldString lens) _ x = x ^. lens-showVal FieldSorry _ _ = ""--showRecordField :: (Double -> String) -> a -> String -> (String, AccessorTree a) -> String -> [String]-showRecordField show' x spaces (getterName, (Field field)) prefix =- [spaces ++ prefix ++ getterName ++ " = " ++ showVal field show' x]-showRecordField show' x spaces (getterName, Data (_,cons) trees) prefix =- (spaces ++ prefixNameEq ++ cons) : showAccTrees show' x trees newSpaces- where- prefixNameEq = prefix ++ getterName ++ " = "- newSpaces = spaces ++ (replicate (length prefixNameEq) ' ')---- version of (init . unlines) which doesn't throw an error on empty input-initUnlines :: [String] -> [Char]-initUnlines [] = ""-initUnlines xs = init (unlines xs)---- | Show a tree of values-showTree :: AccessorTree a -> (Double -> String) -> a -> String-showTree (Data (_,cons) trees) show' x = initUnlines $ cons : showAccTrees show' x trees ""-showTree (Field field) show' x = showVal field show' x---- | Show a list of values--- .--- True --> align the colums, False --> total mayhem-showFlat :: forall a . AccessorTree a -> Bool -> (Double -> String) -> a -> String-showFlat at align show' x = initUnlines $ map f fl- where- n = maximum (map (length . fst) fl)-- f (name, lens) = name ++ spaces ++ " = " ++ showVal lens show' x- where- spaces- | align = replicate (n - length name) ' '- | otherwise = ""-- fl :: [(String, Field a)]- fl = flatten at+import Accessors.Accessors+import Accessors.Instances ()
+ src/Accessors/Accessors.hs view
@@ -0,0 +1,385 @@+{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE InstanceSigs #-}++module Accessors.Accessors+ ( Lookup(..)+ , AccessorTree+ , GAData(..)+ , GAConstructor(..)+ , GASimpleEnum(..)+ , GAField(..)+ , GATip(..)+ , accessors+ , describeGAField+ , sameFieldType+ , flatten+ , flatten'+ , showTree+ , showFlat+ ) where++import GHC.Generics++import Control.Lens ( Lens', Prism', (^.), (.~), preview, prism, withPrism )+import Data.List ( intercalate )+import Text.Printf ( printf )++type AccessorTree a = Either (GAField a) (GAData a)++data GAData a = GAData String (GAConstructor a)++data GAConstructor a =+ GAConstructor String [(Maybe String, AccessorTree a)]+ | GASum (GASimpleEnum a)++data GASimpleEnum a =+ GASimpleEnum+ { eConstructors :: [String]+ , eToString :: a -> String+ , eToIndex :: a -> Int+ , eFromString :: a -> String -> Either String a+ , eFromIndex :: a -> Int -> Either String a+ }++data GAField a =+ FieldDouble (Lens' a Double)+ | FieldFloat (Lens' a Float)+ | FieldInt (Lens' a Int)+ | FieldString (Lens' a String)+ | FieldSorry -- ^ a field which is not yet supported++data GATip a =+ GATipSimpleEnum (GASimpleEnum a)+ | GATipField (GAField a)++showGAData :: String -> GAData a -> [String]+showGAData spaces (GAData name constructors) =+ (spaces ++ "Data " ++ show name) :+ showGAConstructor (spaces ++ " ") constructors++showGAConstructor :: String -> GAConstructor a -> [String]+showGAConstructor spaces (GASum e) = [spaces ++ "[" ++ intercalate ", " (eConstructors e) ++ "]"]+showGAConstructor spaces (GAConstructor name fields) =+ (spaces ++ name) : concatMap (showGAField (spaces ++ " ")) fields++showGAField :: String -> (Maybe String, AccessorTree a) -> [String]+showGAField spaces (name, Left f) = [spaces ++ showMName name ++ " " ++ describeGAField f]+showGAField spaces (name, Right field) =+ showMName name :+ showGAData (spaces ++ " ") field++showMName :: Maybe String -> String+showMName (Just n) = n+showMName Nothing = "()"++instance Show (GAData a) where+ show = unlines . showGAData ""++-- | Return the type of field, such as "Bool", "Double", "String", etc.+describeGAField :: GAField a -> String+describeGAField (FieldDouble _) = "Double"+describeGAField (FieldFloat _) = "Float"+describeGAField (FieldInt _) = "Int"+describeGAField (FieldString _) = "String"+describeGAField FieldSorry = "Sorry"++-- | Returns True if the __type__ of fields is the same.+sameFieldType :: GAField a -> GAField b -> Bool+sameFieldType (FieldDouble _) (FieldDouble _) = True+sameFieldType (FieldFloat _) (FieldFloat _) = True+sameFieldType (FieldInt _) (FieldInt _) = True+sameFieldType (FieldString _) (FieldString _) = True+sameFieldType FieldSorry FieldSorry = True+sameFieldType (FieldDouble _) _ = False+sameFieldType (FieldFloat _) _ = False+sameFieldType (FieldInt _) _ = False+sameFieldType (FieldString _) _ = False+sameFieldType FieldSorry _ = False++accessors :: Lookup a => AccessorTree a+accessors = toAccessorTree id++showMsgs :: [Maybe String] -> String+showMsgs = intercalate "." . map showMName++flatten :: AccessorTree a -> [(String, GATip a)]+flatten = map f . flatten'+ where+ f (x,y) = (showMsgs x, y)++flatten' :: AccessorTree a -> [([Maybe String], GATip a)]+flatten' = flattenChain []+ where+ flattenChain :: [Maybe String] -> AccessorTree a -> [([Maybe String], GATip a)]+ flattenChain msgs (Left f) = [(reverse msgs, GATipField f)]+ flattenChain msgs (Right (GAData _ (GASum simpleEnum))) = [(reverse msgs, GATipSimpleEnum simpleEnum)]+ flattenChain msgs (Right (GAData _ (GAConstructor _ trees))) = concatMap f trees+ where+ f :: (Maybe String, AccessorTree a) -> [([Maybe String], GATip a)]+ f (name, tree) = flattenChain (name:msgs) tree++-- | Things which you can make a tree of labeled getters for.+-- You should derive this using GHC.Generics.+class Lookup a where+ toAccessorTree :: Lens' b a -> AccessorTree b++ default toAccessorTree :: (Generic a, GLookup (Rep a)) => Lens' b a -> AccessorTree b+ toAccessorTree lens0 = gtoAccessorTree (lens0 . repLens)+ where+ repLens :: Lens' a (Rep a p)+ repLens f y = fmap to (f (from y))++class GLookup f where+ gtoAccessorTree :: Lens' b (f a) -> AccessorTree b++class GLookupS f where+ gtoAccessorTreeS :: Lens' b (f a) -> [(Maybe String, AccessorTree b)]++instance Lookup f => GLookup (Rec0 f) where+ gtoAccessorTree :: Lens' b (Rec0 f p) -> AccessorTree b+ gtoAccessorTree lens0 = toAccessorTree (lens0 . rec0Lens)+ where+ rec0Lens :: Lens' (Rec0 f a) f+ rec0Lens f y = fmap K1 (f (unK1 y))++class GEnum a where+ gtoSimpleEnum :: Prism' b (a p) -> [(String, b, b -> Bool)]++instance Constructor c => GEnum (C1 c U1) where+ gtoSimpleEnum :: forall b p . Prism' b (C1 c U1 p) -> [(String, b, b -> Bool)]+ gtoSimpleEnum pr = [(cname, thisOne, isThisOne)]+ where+ thisOne :: b+ thisOne = withPrism pr $ \f _ -> f (M1 U1 :: C1 c U1 p)++ isThisOne :: b -> Bool+ isThisOne b = case preview pr b :: Maybe (C1 c U1 p) of+ Nothing -> False+ Just _ -> True++ cname = conName conError++ conError :: C1 c a p+ conError = error $ "generic-accessors: conName should never access data"++instance (GEnum c1, GEnum c2) => GEnum (c1 :+: c2) where+ gtoSimpleEnum :: forall b p . Prism' b ((c1 :+: c2) p) -> [(String, b, b -> Bool)]+ gtoSimpleEnum pr0 = c1s ++ c2s+ where+ c1s = gtoSimpleEnum ((pr0 . leftPrism) :: Prism' b (c1 p))+ c2s = gtoSimpleEnum ((pr0 . rightPrism) :: Prism' b (c2 p))++ leftPrism :: Prism' ((c1 :+: c2) p) (c1 p)+ leftPrism = prism remitter reviewer+ where+ remitter = L1+ reviewer (L1 l) = Right l+ reviewer x = Left x++ rightPrism :: Prism' ((c1 :+: c2) p) (c2 p)+ rightPrism = prism remitter reviewer+ where+ remitter = R1+ reviewer (R1 l) = Right l+ reviewer x = Left x++instance (Datatype d, GEnum (c1 :+: c2)) => GLookup (D1 d (c1 :+: c2)) where+ gtoAccessorTree :: forall b p . Lens' b (D1 d (c1 :+: c2) p) -> AccessorTree b+ gtoAccessorTree lens0 = Right $ GAData (datatypeName datatypeError) constructor+ where+ datatypeError :: D1 d (c1 :+: c2) p+ datatypeError = error $ "generic-accessors: datatypeName should never access data"++ constructor :: GAConstructor b+ constructor =+ GASum+ GASimpleEnum+ { eConstructors = options+ , eToString = toString+ , eToIndex = toIndex+ , eFromIndex = fromIndex+ , eFromString = fromString+ }+ where+ options = map fst3 simpleEnums+ where+ fst3 (x,_,_) = x++ fromIndex x k+ | k < 0 =+ Left $+ printf "generic-accessors: Error converting Int to Enum: requested negative index (%d)" k+ | k >= length options =+ Left $+ "generic-accessors: Error converting Int to Enum.\n" +++ printf "Requested index %d but there are only %d options." k (length simpleEnums)+ | otherwise = Right $ (lens0 . m1Lens . intLens .~ k) x++ fromString x name = fromString' 0 options+ where+ fromString' k (opt:opts)+ | name == opt = fromIndex x k+ | otherwise = fromString' (k+1) opts+ fromString' _ [] =+ Left $+ "generic-accessors: Error converting from String to Enum: "+ ++ show name ++ "is not one of the constructors."++ toIndex x = x ^. (lens0 . m1Lens . intLens)+ toString x = case safeIndex options index of+ Just r -> r+ Nothing -> error $ unlines+ [ "generic-accessors: eToString: the \"impossible\" happened"+ , printf "Enum is out of bounds (index %d, length %d)." index (length options)+ ]+ where+ index = toIndex x++ simpleEnums :: [(String, (c1 :+: c2) p, (c1 :+: c2) p -> Bool)]+ simpleEnums = gtoSimpleEnum id++ intLens :: Lens' ((c1 :+: c2) p) Int+ intLens f y = fmap fromInt' (f (toInt y))++ fromInt' :: Int -> (c1 :+: c2) p+ fromInt' k = case fromInt k of+ Right r -> r+ Left e -> error e++ fromInt :: Int -> Either String ((c1 :+: c2) p)+ fromInt k = case safeIndex simpleEnums k of+ Nothing -> Left $+ "generic-accessors:\n" +++ "Error converting Int to Enum.\n" +++ printf "Requested index %d but there are only %d options." k (length simpleEnums)+ Just (_, x, _) -> Right x++ toInt :: (c1 :+: c2) p -> Int+ toInt x = toInt' 0 simpleEnums+ where+ toInt' k ((_, _, isVal):others)+ | isVal x = k+ | otherwise = toInt' (k+1) others+ toInt' _ [] =+ error $ unlines+ [ "generic-accessors:"+ , "The \"impossible\" happened converting Enum to Int."+ , "No enum matched the provided one."+ ]++ safeIndex :: [a] -> Int -> Maybe a+ safeIndex (x:_) 0 = Just x+ safeIndex (_:xs) k = safeIndex xs (k-1)+ safeIndex [] _ = Nothing++m1Lens :: Lens' (M1 i c f p) (f p)+m1Lens f y = fmap M1 (f (unM1 y))++instance (Datatype d, Constructor c, GLookupS a) => GLookup (D1 d (C1 c a)) where+ gtoAccessorTree :: forall b p . Lens' b (D1 d (C1 c a) p) -> AccessorTree b+ gtoAccessorTree lens0 = Right $ GAData (datatypeName datatypeError) constructor+ where+ datatypeError :: D1 d (C1 c a) p+ datatypeError = error $ "generic-accessors: datatypeName should never access data"++ constructor :: GAConstructor b+ constructor = gtoAccessorTreeC (lens0 . m1Lens)++gtoAccessorTreeC :: forall c b a p . (Constructor c, GLookupS a) => Lens' b (C1 c a p) -> GAConstructor b+gtoAccessorTreeC lens0 = GAConstructor (conName conError) (gtoAccessorTreeS (lens0 . m1Lens))+ where+ conError :: C1 c a p+ conError = error $ "generic-accessors: conName should never access data"++instance (Selector s, GLookup a) => GLookupS (S1 s a) where+ gtoAccessorTreeS :: Lens' b (S1 s a p) -> [(Maybe String, AccessorTree b)]+ gtoAccessorTreeS lens0 = [(selname, gtoAccessorTree (lens0 . m1Lens))]+ where+ selname = case selName selError of+ "" -> Nothing+ y -> Just y++ selError :: S1 s a p+ selError = error $ "generic-accessors: selName should never access data"++instance GLookupS U1 where+ gtoAccessorTreeS :: Lens' b (U1 p) -> [(Maybe String, AccessorTree b)]+ gtoAccessorTreeS _ = []++instance (GLookupS f, GLookupS g) => GLookupS (f :*: g) where+ gtoAccessorTreeS :: Lens' b ((f :*: g) p) -> [(Maybe String, AccessorTree b)]+ gtoAccessorTreeS lens0 = tf ++ tg+ where+ tf = gtoAccessorTreeS (lens0 . leftLens)+ tg = gtoAccessorTreeS (lens0 . rightLens)++ leftLens :: Lens' ((f :*: g) a) (f a)+ leftLens f (x :*: y) = fmap (\x' -> x' :*: y ) (f x)++ rightLens :: Lens' ((f :*: g) a) (g a)+ rightLens f (x :*: y) = fmap (\y' -> x :*: y') (f y)+++showAccTrees :: (Double -> String) -> a+ -> [(Maybe String, AccessorTree a)] -> String+ -> [String]+showAccTrees show' x trees spaces = concat cs ++ [spaces ++ "}"]+ where+ cs = zipWith (showRecordField show' x spaces) trees ("{ " : repeat ", ")++showFieldVal :: GAField a -> (Double -> String) -> a -> String+showFieldVal (FieldInt lens) _ x = show (x ^. lens)+showFieldVal (FieldDouble lens) show' x = show' (x ^. lens)+showFieldVal (FieldFloat lens) show' x = show' (realToFrac (x ^. lens))+showFieldVal (FieldString lens) _ x = x ^. lens+showFieldVal FieldSorry _ _ = ""++showTipVal :: GATip a -> (Double -> String) -> a -> String+showTipVal (GATipField f) sh x = showFieldVal f sh x+showTipVal (GATipSimpleEnum simpleEnum) _ x = eToString simpleEnum x++showRecordField :: (Double -> String) -> a -> String -> (Maybe String, AccessorTree a) -> String -> [String]+showRecordField show' x spaces (getterName, (Left field)) prefix =+ [spaces ++ prefix ++ showMName getterName ++ " = " ++ showFieldVal field show' x]+showRecordField _ x spaces (getterName, Right (GAData _ (GASum simpleEnum))) prefix =+ [spaces ++ prefix ++ showMName getterName ++ " = " ++ eToString simpleEnum x]+showRecordField show' x spaces (getterName, Right (GAData _ (GAConstructor cons trees))) prefix =+ (spaces ++ prefixNameEq ++ cons) : showAccTrees show' x trees newSpaces+ where+ prefixNameEq = prefix ++ showMName getterName ++ " = "+ newSpaces = spaces ++ (replicate (length prefixNameEq) ' ')++-- version of (init . unlines) which doesn't throw an error on empty input+initUnlines :: [String] -> [Char]+initUnlines [] = ""+initUnlines xs = init (unlines xs)++-- | Show a tree of values+showTree :: AccessorTree a -> (Double -> String) -> a -> String+showTree (Right (GAData _ (GASum simpleEnum))) _ x = eToString simpleEnum x+showTree (Right (GAData _ (GAConstructor cons trees))) show' x =+ initUnlines $ cons : showAccTrees show' x trees ""+showTree (Left field) show' x = showFieldVal field show' x++-- | Show a list of values+-- .+-- True --> align the colums, False --> total mayhem+showFlat :: forall a . AccessorTree a -> Bool -> (Double -> String) -> a -> String+showFlat at align show' x = initUnlines $ map f fl+ where+ n = maximum (map (length . fst) fl)++ f (name, lens) = name ++ spaces ++ " = " ++ showTipVal lens show' x+ where+ spaces+ | align = replicate (n - length name) ' '+ | otherwise = ""++ fl :: [(String, GATip a)]+ fl = flatten at
+ src/Accessors/Dynamic.hs view
@@ -0,0 +1,221 @@+{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveDataTypeable #-}++module Accessors.Dynamic+ ( DTree, DData(..), DConstructor(..), DSimpleEnum(..), DField(..)+ , toDData, updateLookupable, describeDField, sameDFieldType+ -- * some utility functions for working with DSimpleEnums+ , denumToString, denumToStringOrMsg, denumSetString, denumSetIndex+ ) where++import GHC.Generics++import Data.Binary ( Binary )+import Data.Serialize ( Serialize )+import Data.Data ( Data )+import Data.List ( intercalate )+import Data.Typeable ( Typeable )+import Control.Lens+import Text.Printf ( printf )++import Accessors++type DTree = Either DField DData++data DData = DData String DConstructor+ deriving (Generic, Show, Eq, Ord, Data, Typeable)+instance Serialize DData+instance Binary DData++data DConstructor =+ DConstructor String [(Maybe String, DTree)]+ | DSum DSimpleEnum+ deriving (Generic, Show, Eq, Ord, Data, Typeable)+instance Serialize DConstructor+instance Binary DConstructor++data DSimpleEnum = DSimpleEnum [String] Int+ deriving (Generic, Show, Eq, Ord, Data, Typeable)+instance Serialize DSimpleEnum+instance Binary DSimpleEnum++-- | a dynamic field+data DField =+ DDouble Double+ | DFloat Float+ | DInt Int+ | DString String+ | DSorry+ deriving (Generic, Show, Eq, Ord, Data, Typeable)+instance Serialize DField+instance Binary DField++-- | Get the constructor string or an error message.+denumToString :: DSimpleEnum -> Either String String+denumToString (DSimpleEnum _ k)+ | k < 0 = Left $ printf "denumToString: index %d is negative" k+denumToString (DSimpleEnum constructors k) = safeIndex constructors k+ where+ safeIndex (x:_) 0 = Right x+ safeIndex (_:xs) j = safeIndex xs (j-1)+ safeIndex [] _ =+ Left $+ printf "denumToString: index %d is too large (%d constructors)" k (length constructors)++-- | Get the constructor string or an error message without telling which is which.+denumToStringOrMsg :: DSimpleEnum -> String+denumToStringOrMsg d = case denumToString d of+ Left msg -> msg+ Right r -> r++-- | Try to update an enum with its constructor. Fail if not a valid constructor.+denumSetString :: DSimpleEnum -> String -> Either String DSimpleEnum+denumSetString (DSimpleEnum options _) txt = safeLookup options 0+ where+ safeLookup (opt:opts) k+ | opt == txt = Right (DSimpleEnum options k)+ | otherwise = safeLookup opts (k + 1)+ safeLookup [] _ = Left $ printf "denumSetString: %s is not a valid constructor" txt++-- | Try to update an enum with its index. Fail if out of bounds.+denumSetIndex :: DSimpleEnum -> Int -> Either String DSimpleEnum+denumSetIndex (DSimpleEnum constructors _) k+ | k < 0 = Left $ printf "denumSetIndex: index %d is negative" k+ | k >= length constructors =+ Left $+ printf "denumSetIndex: index %d is too large (%d constructors)" k (length constructors)+ | otherwise = Right $ DSimpleEnum constructors k++-- | Returns True if the __type__ of fields is the same.+sameDFieldType :: DField -> DField -> Bool+sameDFieldType (DDouble _) (DDouble _) = True+sameDFieldType (DFloat _) (DFloat _) = True+sameDFieldType (DInt _) (DInt _) = True+sameDFieldType (DString _) (DString _) = True+sameDFieldType DSorry DSorry = True+sameDFieldType (DDouble _) _ = False+sameDFieldType (DFloat _) _ = False+sameDFieldType (DInt _) _ = False+sameDFieldType (DString _) _ = False+sameDFieldType DSorry _ = False++describeDField :: DField -> String+describeDField (DInt _) = "Int"+describeDField (DDouble _) = "Double"+describeDField (DFloat _) = "Float"+describeDField (DString _) = "String"+describeDField DSorry = "Sorry"++-- | convert to a dynamic value+toDData :: forall a . Lookup a => a -> DTree+toDData x = toDData' accessors+ where+ toDData' :: Either (GAField a) (GAData a) -> DTree+ toDData' (Right (GAData dname constructor)) =+ Right $ DData dname (toDConstructor constructor)+ toDData' (Left field) = Left (toDField field)++ toDConstructor :: GAConstructor a -> DConstructor+ toDConstructor (GASum e) =+ DSum (DSimpleEnum (eConstructors e) (eToIndex e x))+ + toDConstructor (GAConstructor cname fields) =+ DConstructor cname $ map (\(n, f) -> (n, toDData' f)) fields++ toDField :: GAField a -> DField+ toDField (FieldInt f) = DInt (x ^. f)+ toDField (FieldDouble f) = DDouble (x ^. f)+ toDField (FieldFloat f) = DFloat (x ^. f)+ toDField (FieldString f) = DString (x ^. f)+ toDField FieldSorry = DSorry+++-- | Update something using a dynamic representation+updateLookupable :: Lookup a => a -> DTree -> Either String a+updateLookupable x0 dtree = updateData x0 accessors dtree++updateData :: forall a+ . a+ -> Either (GAField a) (GAData a)+ -> DTree+ -> Either String a+updateData x0 (Left afield) (Left dfield) = updateField x0 afield dfield+updateData x0 (Right (GAData adataName acon)) (Right (DData ddataName dcon))+ | adataName /= ddataName =+ Left $+ "dynamic datatype name " ++ show ddataName +++ " don't match accessor datatype names " ++ show adataName+ | otherwise = updateConstructor x0 acon dcon+updateData _ (Left field) (Right (DData n _)) =+ Left $ "got GAField (" ++ describeGAField field ++ ") for accessor tree but DData (" ++ show n ++ ") for dynamic tree"+updateData _ (Right (GAData n _)) (Left field) =+ Left $ "got GAData for accessor tree (" ++ show n ++ ") but DField (" ++ describeDField field++ ") for dynamic tree"++showList' :: [String] -> String+showList' xs = "[" ++ intercalate ", " xs ++ "]"++updateConstructor :: forall a+ . a+ -> GAConstructor a+ -> DConstructor+ -> Either String a+updateConstructor x (GASum aenum) (DSum (DSimpleEnum dnames k))+ | anames /= dnames =+ Left $+ "accessor sum options " ++ showList' anames +++ " doesn't match dynamic sum options " ++ showList' dnames+ | otherwise = eFromIndex aenum x k+ where+ anames = eConstructors aenum+updateConstructor x0 (GAConstructor aconName afields) (DConstructor dconName dfields)+ | aconName /= dconName =+ Left $+ "dynamic constructor name " ++ show dconName +++ " don't match accessor constructor names " ++ show aconName+ | length afields /= length dfields = lengthMismatch+ | otherwise = f x0 afields dfields+ where+ lengthMismatch =+ Left $+ "dynamic fields have different length than accessor fields\n" +++ "dynamic fields: " ++ show (map fst dfields) ++ "\n" +++ "accessor fields: " ++ show (map fst afields)+ + f :: a+ -> [(Maybe String, Either (GAField a) (GAData a))]+ -> [(Maybe String, DTree)]+ -> Either String a+ f x ((aname, afield):as) ((dname, dfield):ds)+ | aname /= dname =+ Left $+ "accessor selector name " ++ show aname +++ " doesn't match dynamic selector name " ++ show dname+ | otherwise = case updateData x afield dfield of+ Left msg -> Left $ "error updating selector " ++ show aname ++ ": " ++ msg+ Right r -> f r as ds+ f x [] [] = Right x+ -- this should never happen:+ f _ _ _ = lengthMismatch+updateConstructor _ (GAConstructor aconName _) (DSum (DSimpleEnum dnames _)) =+ Left $ "got GAConstructor (" ++ aconName ++ ") but DSum ([" ++ showList' dnames ++ "])"+updateConstructor _ (GASum aenum) (DConstructor dconName _) =+ Left $ "got GASum ([" ++ showList' (eConstructors aenum) ++ "]) but DConstructor (" ++ dconName ++ ")"+++updateField :: a -> GAField a -> DField -> Either String a+updateField x0 (FieldDouble f) (DDouble x) = Right $ (f .~ x) x0+updateField x0 (FieldFloat f) (DFloat x) = Right $ (f .~ x) x0+updateField x0 (FieldInt f) (DInt x) = Right $ (f .~ x) x0+updateField x0 (FieldString f) (DString x) = Right $ (f .~ x) x0+updateField x0 FieldSorry _ = Right x0+updateField _ f@(FieldDouble _) d = Left (fieldMismatch f d)+updateField _ f@(FieldFloat _) d = Left (fieldMismatch f d)+updateField _ f@(FieldInt _) d = Left (fieldMismatch f d)+updateField _ f@(FieldString _) d = Left (fieldMismatch f d)++fieldMismatch :: GAField a -> DField -> String+fieldMismatch f d =+ "accessor GAField " ++ describeGAField f +++ " got incompatible dynamic DField " ++ describeDField d
+ src/Accessors/Instances.hs view
@@ -0,0 +1,219 @@+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances #-}++module Accessors.Instances () where++import Control.Lens ( Lens' )+import qualified Linear+import GHC.Word+import Data.Int+import Foreign.C.Types+import SpatialMath ( Euler )+import SpatialMathT ( V3T(..), Rot(..) )++import Accessors.Accessors ( Lookup(..), GAData(..), GAConstructor(..), GAField(..) )++-- tuple instances+instance (Lookup a, Lookup b) => Lookup (a, b) where+ toAccessorTree lens0 =+ Right $+ GAData "(,)" $+ GAConstructor "(,)"+ [ (Just "(x,_)", toAccessorTree (lens0 . lens1))+ , (Just "(_,x)", toAccessorTree (lens0 . lens2))+ ]+ where+ lens1 :: Lens' (a, b) a+ lens1 f (x, y) = fmap (\x' -> (x', y)) (f x)++ lens2 :: Lens' (a, b) b+ lens2 f (x, y) = fmap (\y' -> (x, y')) (f y)++instance (Lookup a, Lookup b, Lookup c) => Lookup (a, b, c) where+ toAccessorTree lens0 =+ Right $+ GAData "(,,)" $+ GAConstructor "(,,)"+ [ (Just "(x,_,_)", toAccessorTree (lens0 . lens1))+ , (Just "(_,x,_)", toAccessorTree (lens0 . lens2))+ , (Just "(_,_,x)", toAccessorTree (lens0 . lens3))+ ]+ where+ lens1 :: Lens' (a, b, c) a+ lens1 f (x, y, z) = fmap (\x' -> (x', y, z)) (f x)+ lens2 :: Lens' (a, b, c) b+ lens2 f (x, y, z) = fmap (\y' -> (x, y', z)) (f y)+ lens3 :: Lens' (a, b, c) c+ lens3 f (x, y, z) = fmap (\z' -> (x, y, z')) (f z)++instance (Lookup a, Lookup b, Lookup c, Lookup d) => Lookup (a, b, c, d) where+ toAccessorTree lens0 =+ Right $+ GAData "(,,,)" $+ GAConstructor "(,,,)"+ [ (Just "(x,_,_,_)", toAccessorTree (lens0 . lens1))+ , (Just "(_,x,_,_)", toAccessorTree (lens0 . lens2))+ , (Just "(_,_,x,_)", toAccessorTree (lens0 . lens3))+ , (Just "(_,_,_,x)", toAccessorTree (lens0 . lens4))+ ]+ where+ lens1 :: Lens' (a, b, c, d) a+ lens1 f (x, y, z, w) = fmap (\x' -> (x', y, z, w)) (f x)+ lens2 :: Lens' (a, b, c, d) b+ lens2 f (x, y, z, w) = fmap (\y' -> (x, y', z, w)) (f y)+ lens3 :: Lens' (a, b, c, d) c+ lens3 f (x, y, z, w) = fmap (\z' -> (x, y, z', w)) (f z)+ lens4 :: Lens' (a, b, c, d) d+ lens4 f (x, y, z, w) = fmap (\w' -> (x, y, z, w')) (f w)+++-- some instance from linear+instance Lookup a => Lookup (Linear.V0 a) where+ toAccessorTree _ =+ Right $ GAData "V0" $ GAConstructor "V0" []+instance Lookup a => Lookup (Linear.V1 a) where+ toAccessorTree lens0 =+ Right $ GAData "V1" $ GAConstructor "V1"+ [(Just "x", toAccessorTree (lens0 . Linear._x))]++instance Lookup a => Lookup (Linear.V2 a) where+ toAccessorTree lens0 =+ Right $ GAData "V2" $ GAConstructor "V2"+ [ (Just "x", toAccessorTree (lens0 . Linear._x))+ , (Just "y", toAccessorTree (lens0 . Linear._y))+ ]++instance Lookup a => Lookup (Linear.V3 a) where+ toAccessorTree lens0 =+ Right $ GAData "V3" $ GAConstructor "V3"+ [ (Just "x", toAccessorTree (lens0 . Linear._x))+ , (Just "y", toAccessorTree (lens0 . Linear._y))+ , (Just "z", toAccessorTree (lens0 . Linear._z))+ ]+instance Lookup a => Lookup (Linear.V4 a) where+ toAccessorTree lens0 =+ Right $ GAData "V4" $ GAConstructor "V4"+ [ (Just "x", toAccessorTree (lens0 . Linear._x))+ , (Just "y", toAccessorTree (lens0 . Linear._y))+ , (Just "z", toAccessorTree (lens0 . Linear._z))+ , (Just "w", toAccessorTree (lens0 . Linear._w))+ ]+instance Lookup a => Lookup (Linear.Quaternion a) where+ toAccessorTree lens0 =+ Right $ GAData "Quaternion" $ GAConstructor "Quaternion"+ [ (Just "q0", toAccessorTree (lens0 . Linear._e))+ , (Just "q1", toAccessorTree (lens0 . Linear._i))+ , (Just "q2", toAccessorTree (lens0 . Linear._j))+ , (Just "q3", toAccessorTree (lens0 . Linear._k))+ ]++-- basic types+instance Lookup () where -- hack to get dummy tree+ toAccessorTree _ = Left FieldSorry+instance Lookup Int where+ toAccessorTree lens = Left (FieldInt lens)+instance Lookup Float where+ toAccessorTree lens = Left (FieldFloat lens)+instance Lookup Double where+ toAccessorTree lens = Left (FieldDouble lens)+instance Lookup Bool+instance Lookup String where+ toAccessorTree lens = Left (FieldString lens)++-- Word types+instance Lookup Word where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Word8 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Word16 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Word32 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Word64 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))++-- Int types+instance Lookup Int8 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Int16 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Int32 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup Int64 where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))++-- C types+-- todo(greg): some of these have inappropriate fields+instance Lookup CChar where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CSChar where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CUChar where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CShort where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CUShort where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CInt where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CUInt where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CLong where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CULong where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CPtrdiff where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CSize where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CWchar where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CSigAtomic where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CLLong where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CULLong where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CIntPtr where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CUIntPtr where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CIntMax where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CUIntMax where+ toAccessorTree lens0 = Left (FieldInt (lens0 . integralLens))+instance Lookup CClock where+ toAccessorTree lens0 = Left (FieldInt (lens0 . clockLens))+ where+ clockLens f (CClock x) = fmap (CClock . fromIntegral) (f (fromIntegral x))+instance Lookup CTime where+ toAccessorTree lens0 = Left (FieldInt (lens0 . timeLens))+ where+ timeLens f (CTime x) = fmap (CTime . fromIntegral) (f (fromIntegral x))+instance Lookup CUSeconds where+ toAccessorTree lens0 = Left (FieldInt (lens0 . usecondsLens))+ where+ usecondsLens f (CUSeconds x) = fmap (CUSeconds . fromIntegral) (f (fromIntegral x))+instance Lookup CSUSeconds where+ toAccessorTree lens0 = Left (FieldInt (lens0 . susecondsLens))+ where+ susecondsLens f (CSUSeconds x) = fmap (CSUSeconds . fromIntegral) (f (fromIntegral x))+instance Lookup CFloat where+ toAccessorTree lens0 = Left (FieldDouble (lens0 . realFracLens))+instance Lookup CDouble where+ toAccessorTree lens0 = Left (FieldDouble (lens0 . realFracLens))++{-# INLINE integralLens #-}+integralLens :: Integral a => Lens' a Int+integralLens f x = fmap fromIntegral (f (fromIntegral x))++{-# INLINE realFracLens #-}+realFracLens :: (Fractional a, Real a) => Lens' a Double+realFracLens f x = fmap realToFrac (f (realToFrac x))++-- other types+instance Lookup a => Lookup (Rot f1 f2 a) where+ toAccessorTree lens0 = toAccessorTree (lens0 . (\f x -> fmap Rot (f (unR x))))+instance Lookup a => Lookup (V3T f a) where+ toAccessorTree lens0 = toAccessorTree (lens0 . (\f x -> fmap V3T (f (unV x))))+instance Lookup a => Lookup (Euler a)
tests/Tests.hs view
@@ -13,11 +13,13 @@ import Test.Framework.Providers.HUnit ( testCase ) import Accessors+import Accessors.Dynamic main :: IO () main = do defaultMainWithOpts [ accessorTests+ , dynamicTests ] opts @@ -34,27 +36,29 @@ data Xyz a = Xyz { xx :: Int , yy :: Double , zz :: Float+ , bb :: (Bool, Bool, Bool) , ww :: a- } deriving (Generic)-data One = MkOne { one :: Double } deriving (Generic)+ } deriving (Generic, Show)+data One = MkOne { one :: Double+ } deriving (Generic, Show) data Foo = MkFoo { aaa :: Int , bbb :: Xyz Int , lol :: Bool , notlol :: Bool , yoyo :: Xyz (Xyz Double) , ccc :: One- } deriving (Generic)+ } deriving (Generic, Show) instance Lookup One instance Lookup a => Lookup (Xyz a) instance Lookup Foo yo :: Xyz (Xyz Double)-yo = Xyz 42 45 2000 (Xyz 2 3 4 5)+yo = Xyz 42 45 2000 (True, True, False) (Xyz 2 3 4 (False, True, False) 5) foo :: Foo-foo = MkFoo 2 (Xyz 6 7 8 9) True False yo (MkOne 17)+foo = MkFoo 2 (Xyz 6 7 8 (True, False, False) 9) True False yo (MkOne 17) -yup :: AccessorTree Foo+yup :: Either (GAField Foo) (GAData Foo) yup = accessors @@ -66,6 +70,14 @@ , testCase "showFlat (aligned)" flatTestAligned ] +dynamicTests :: Test+dynamicTests =+ testGroup "dynamic"+ [ testCase "toDValue" toDValueTest+ , testCase "updateDValueTest" updateDValueTest+ , testCase "badupdateDValueTest" badUpdateDValueTest+ ]+ assertEqualString :: String -> String -> HUnit.Assertion assertEqualString x y = HUnit.assertBool msg (x == y) where@@ -75,6 +87,92 @@ y ++ "\n-----------------------------------------------" +assertEqualString' :: Either String String -> Either String String -> HUnit.Assertion+assertEqualString' ex ey = HUnit.assertBool msg (ex == ey)+ where+ x = case ex of+ Left r -> r+ Right r -> r+ y = case ey of+ Left r -> r+ Right r -> r+ msg = "------------------ expected: ------------------\n" +++ x +++ "\n------------------ but got: -------------------\n" +++ y +++ "\n-----------------------------------------------"++toDValueTest :: HUnit.Assertion+toDValueTest = assertEqualString x y+ where+ x = "Right (DData \"Xyz\" (DConstructor \"Xyz\" [(Just \"xx\",Left (DInt 1)),(Just \"yy\",Left (DDouble 2.0)),(Just \"zz\",Left (DFloat 3.0)),(Just \"bb\",Right (DData \"(,,)\" (DConstructor \"(,,)\" [(Just \"(x,_,_)\",Right (DData \"Bool\" (DSum (DSimpleEnum [\"False\",\"True\"] 1)))),(Just \"(_,x,_)\",Right (DData \"Bool\" (DSum (DSimpleEnum [\"False\",\"True\"] 0)))),(Just \"(_,_,x)\",Right (DData \"Bool\" (DSum (DSimpleEnum [\"False\",\"True\"] 1))))]))),(Just \"ww\",Right (DData \"One\" (DConstructor \"MkOne\" [(Just \"one\",Left (DDouble 4.0))])))]))"++ y = show (toDData (Xyz 1 2 3 (True, False, True) (MkOne 4)))++updateDValueTest :: HUnit.Assertion+updateDValueTest = assertEqualString' (fmap show x) (fmap show y)+ where+ x0 :: Xyz One+ x0 = Xyz 1 2 3 (True, False, True) (MkOne 4)++ dvalue =+ DData "Xyz" $+ DConstructor "Xyz" $+ [ (Just "xx", Left (DInt 10))+ , (Just "yy", Left (DDouble 20.0))+ , (Just "zz", Left (DFloat 30.0))+ , ( Just "bb"+ , Right (DData "(,,)"+ (DConstructor "(,,)"+ [ (Just "(x,_,_)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 0))))+ , (Just "(_,x,_)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 1))))+ , (Just "(_,_,x)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 1))))+ ]))+ )+ , (Just "ww", Right (DData "One"+ (DConstructor "MkOne"+ [ (Just "one", Left (DDouble 40.0))+ ])))+ ]++ x :: Either String (Xyz One)+ x = Right $ Xyz 10 20 30 (False, True, True) (MkOne 40)++ y :: Either String (Xyz One)+ y = updateLookupable x0 (Right dvalue)++badUpdateDValueTest :: HUnit.Assertion+badUpdateDValueTest = assertEqualString' (fmap show x) (fmap show y)+ where+ x0 :: Xyz One+ x0 = Xyz 1 2 3 (True, False, True) (MkOne 4)++ dvalue =+ DData "Xyz" $+ DConstructor "Xyz" $+ [ (Just "xx", Left (DInt 10))+ , (Just "yy", Left (DDouble 20.0))+ , (Just "zz", Left (DFloat 30.0))+ , ( Just "b"+ , Right (DData "(,,)"+ (DConstructor "(,,)"+ [ (Just "(x,_,_)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 0))))+ , (Just "(_,x,_)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 1))))+ , (Just "(_,_,x)", Right (DData "Bool" (DSum (DSimpleEnum ["False", "True"] 1))))+ ]))+ )+ , (Just "ww", Right (DData "One"+ (DConstructor "MkOne"+ [ (Just "one", Left (DDouble 40.0))+ ])))+ ]++ x :: Either String (Xyz One)+ x = Left "accessor selector name Just \"bb\" doesn't match dynamic selector name Just \"b\""++ y :: Either String (Xyz One)+ y = updateLookupable x0 (Right dvalue)+ treeTest :: HUnit.Assertion treeTest = assertEqualString x y where@@ -85,6 +183,11 @@ , " { xx = 6" , " , yy = 7.00e0" , " , zz = 8.00e0"+ , " , bb = (,,)"+ , " { (x,_,_) = True"+ , " , (_,x,_) = False"+ , " , (_,_,x) = False"+ , " }" , " , ww = 9" , " }" , ", lol = True"@@ -93,10 +196,20 @@ , " { xx = 42" , " , yy = 4.50e1" , " , zz = 2.00e3"+ , " , bb = (,,)"+ , " { (x,_,_) = True"+ , " , (_,x,_) = True"+ , " , (_,_,x) = False"+ , " }" , " , ww = Xyz" , " { xx = 2" , " , yy = 3.00e0" , " , zz = 4.00e0"+ , " , bb = (,,)"+ , " { (x,_,_) = False"+ , " , (_,x,_) = True"+ , " , (_,_,x) = False"+ , " }" , " , ww = 5.00e0" , " }" , " }"@@ -115,15 +228,24 @@ , "bbb.xx = 6" , "bbb.yy = 7.00e0" , "bbb.zz = 8.00e0"+ , "bbb.bb.(x,_,_) = True"+ , "bbb.bb.(_,x,_) = False"+ , "bbb.bb.(_,_,x) = False" , "bbb.ww = 9" , "lol = True" , "notlol = False" , "yoyo.xx = 42" , "yoyo.yy = 4.50e1" , "yoyo.zz = 2.00e3"+ , "yoyo.bb.(x,_,_) = True"+ , "yoyo.bb.(_,x,_) = True"+ , "yoyo.bb.(_,_,x) = False" , "yoyo.ww.xx = 2" , "yoyo.ww.yy = 3.00e0" , "yoyo.ww.zz = 4.00e0"+ , "yoyo.ww.bb.(x,_,_) = False"+ , "yoyo.ww.bb.(_,x,_) = True"+ , "yoyo.ww.bb.(_,_,x) = False" , "yoyo.ww.ww = 5.00e0" , "ccc.one = 1.70e1" ]@@ -133,20 +255,29 @@ flatTestAligned = assertEqualString x y where x = init $ unlines- [ "aaa = 2"- , "bbb.xx = 6"- , "bbb.yy = 7.00e0"- , "bbb.zz = 8.00e0"- , "bbb.ww = 9"- , "lol = True"- , "notlol = False"- , "yoyo.xx = 42"- , "yoyo.yy = 4.50e1"- , "yoyo.zz = 2.00e3"- , "yoyo.ww.xx = 2"- , "yoyo.ww.yy = 3.00e0"- , "yoyo.ww.zz = 4.00e0"- , "yoyo.ww.ww = 5.00e0"- , "ccc.one = 1.70e1"+ [ "aaa = 2"+ , "bbb.xx = 6"+ , "bbb.yy = 7.00e0"+ , "bbb.zz = 8.00e0"+ , "bbb.bb.(x,_,_) = True"+ , "bbb.bb.(_,x,_) = False"+ , "bbb.bb.(_,_,x) = False"+ , "bbb.ww = 9"+ , "lol = True"+ , "notlol = False"+ , "yoyo.xx = 42"+ , "yoyo.yy = 4.50e1"+ , "yoyo.zz = 2.00e3"+ , "yoyo.bb.(x,_,_) = True"+ , "yoyo.bb.(_,x,_) = True"+ , "yoyo.bb.(_,_,x) = False"+ , "yoyo.ww.xx = 2"+ , "yoyo.ww.yy = 3.00e0"+ , "yoyo.ww.zz = 4.00e0"+ , "yoyo.ww.bb.(x,_,_) = False"+ , "yoyo.ww.bb.(_,x,_) = True"+ , "yoyo.ww.bb.(_,_,x) = False"+ , "yoyo.ww.ww = 5.00e0"+ , "ccc.one = 1.70e1" ] y = showFlat yup True (printf "%.2e") foo