{-# LANGUAGE FlexibleContexts #-}{-# LANGUAGE DeriveDataTypeable #-}------------------------------------------------------------- Module : Data.Object-- Copyright : Michael Snoyman-- License : BSD3---- Maintainer : Michael Snoyman <michael@snoyman.com>-- Stability : Stable-- Portability : portable---- These objects show up in different places, eg JSON, Yaml.-- By providing a representation in a separate repository,-- other libraries can share a single representation of-- these structures.------------------------------------------------------------- | The core of this package is the 'Object' data type, which is used for-- handling scalars, sequences and mappings in a nested manner. This-- is the same structure used in JSON or Yaml data.---- The 'Object' data type is polymorphic in its keys and values. Submodules-- within this package provide more concrete datatypes, such as a 'String'-- 'Object' and a specialized scalar type.---- Besides the 'Object' data type, there are utility functions and type classes-- for converting objects around. Care has been taken to avoid any overloaded-- instances for these type classes.moduleData.Object(-- * Object data typeObject(..)-- ** Convenient type synonyms,StringObject,TextObject-- ** Scalar data type,Scalar(..),ScalarObject-- * Basic mapping of keys and values,mapKeys,mapValues,mapKeysValues,mapKeysValuesA,mapKeysValuesM-- * Extracting underlying values,ObjectExtractError(..),fromScalar,fromSequence,fromMapping-- * Lookups,lookupObject,lookupScalar,lookupSequence,lookupMapping)whereimportControl.ArrowimportControl.ApplicativeimportControl.Monad(ap,(<=<))importPreludehiding(mapM,sequence)importData.Foldablehiding(concatMap,concat)importData.TraversableimportData.MonoidimportControl.Exception(Exception)importData.Data(Data,Typeable)importControl.FailureimportData.Text(Text)importData.Time(UTCTime)importData.ByteString(ByteString)-- | Can represent nested values as scalars, sequences and mappings. A-- sequence is synonymous with a list, while a mapping is synonymous with a-- list of pairs.---- Note that instances of standard library type classes for this data type-- leave the key untouched while altering the value. For example, the 'Functor'-- instance defines 'fmap' to be synonymous with 'mapValues'.dataObjectkeyval=Mapping[(key,Objectkeyval)]|Sequence[Objectkeyval]|Scalarvalderiving(Show,Eq,Data,Typeable)typeStringObject=ObjectStringString-- | 'Object's with keys and values of strict 'Text'.typeTextObject=ObjectTextTextdataScalar=NumericRational|TextText|BinaryByteString|BoolBool|TimestampUTCTime|NulltypeScalarObject=ObjectStringScalarinstanceFunctor(Objectkey)wherefmap=mapValuesinstanceFoldable(Objectkey)wherefoldMapf(Scalarv)=fvfoldMapf(Sequencevs)=mconcat$map(foldMapf)vsfoldMapf(Mappingpairs)=mconcat$map(foldMapf.snd)pairsinstanceTraversable(Objectkey)wheretraversef(Scalarv)=Scalar<$>fvtraversef(Sequencevs)=Sequence<$>traverse(traversef)vstraversef(Mappingpairs)=Mapping<$>traverse(traverse'(traversef))pairs-- It would be nice if there were an "instance Traversable ((,) a)", but I-- won't make an orphan instance simply for convenience. Instead:traverse'::Applicativef=>(a->fb)->(x,a)->f(x,b)traverse'f(x,a)=(,)x<$>fajoinObj::Objectkey(Objectkeyscalar)->ObjectkeyscalarjoinObj(Scalarx)=xjoinObj(Sequencexs)=Sequence(mapjoinObjxs)joinObj(Mappingxs)=Mapping(map(secondjoinObj)xs)instanceMonad(Objectkey)wherereturn=Scalarx>>=f=joinObj.fmapf$xinstanceApplicative(Objectkey)wherepure=Scalar(<*>)=ap-- | Apply some conversion to the keys of an 'Object', leaving the values-- unchanged.mapKeys::(keyIn->keyOut)->ObjectkeyInval->ObjectkeyOutvalmapKeys=flipmapKeysValuesid-- | Apply some conversion to the values of an 'Object', leaving the keys-- unchanged. This is equivalent to 'fmap'.mapValues::(valIn->valOut)->ObjectkeyvalIn->ObjectkeyvalOutmapValues=mapKeysValuesid-- | Apply a conversion to both the keys and values of an 'Object'.mapKeysValues::(keyIn->keyOut)->(valIn->valOut)->ObjectkeyInvalIn->ObjectkeyOutvalOutmapKeysValues_fv(Scalarv)=Scalar$fvvmapKeysValuesfkfv(Sequenceos)=Sequence$map(mapKeysValuesfkfv)osmapKeysValuesfkfv(Mappingpairs)=Mapping$map(fk***mapKeysValuesfkfv)pairs-- | Apply an 'Applicative' conversion to both the keys and values of an-- 'Object'.mapKeysValuesA::Applicativef=>(keyIn->fkeyOut)->(valIn->fvalOut)->ObjectkeyInvalIn->f(ObjectkeyOutvalOut)mapKeysValuesA_fv(Scalarv)=Scalar<$>fvvmapKeysValuesAfkfv(Sequenceos)=Sequence<$>traverse(mapKeysValuesAfkfv)osmapKeysValuesAfkfv(Mappingpairs)=Mapping<$>traverse(uncurry(liftA2(,)).(fk***mapKeysValuesAfkfv))pairs-- | The same as 'mapKeysValuesA', but using a 'Monad' since some people are-- more comfortable with 'Monad's and not all 'Monad's are 'Applicative'.mapKeysValuesM::Monadm=>(keyIn->mkeyOut)->(valIn->mvalOut)->ObjectkeyInvalIn->m(ObjectkeyOutvalOut)mapKeysValuesMfkfv=letfk'=WrapMonad.fkfv'=WrapMonad.fvinunwrapMonad.mapKeysValuesAfk'fv'-- | An error value returned when an unexpected node is encountered, eg you-- were expecting a 'Scalar' and found a 'Mapping'.dataObjectExtractError=ExpectedScalar|ExpectedSequence|ExpectedMapping|MissingKeyStringderiving(Typeable,Show)instanceExceptionObjectExtractError-- | Extract a scalar from the input, failing if the input is a sequence or-- mapping.fromScalar::FailureObjectExtractErrorm=>Objectkv->mvfromScalar(Scalars)=returnsfromScalar_=failureExpectedScalar-- | Extract a sequence from the input, failing if the input is a scalar or-- mapping.fromSequence::FailureObjectExtractErrorm=>Objectkv->m[Objectkv]fromSequence(Sequences)=returnsfromSequence_=failureExpectedSequence-- | Extract a mapping from the input, failing if the input is a scalar or-- sequence.fromMapping::FailureObjectExtractErrorm=>Objectkv->m[(k,Objectkv)]fromMapping(Mappingm)=returnmfromMapping_=failureExpectedMappinglookupObject::(Showk,Eqk,FailureObjectExtractErrorm)=>k->[(k,Objectkv)]->m(Objectkv)lookupObjectkpairs=caselookupkpairsofNothing->failure$MissingKey$showkJustv->returnvlookupScalar::(Showk,Eqk,FailureObjectExtractErrorm)=>k->[(k,Objectkv)]->mvlookupScalark=fromScalar<=<lookupObjectklookupSequence::(Showk,Eqk,FailureObjectExtractErrorm)=>k->[(k,Objectkv)]->m[Objectkv]lookupSequencek=fromSequence<=<lookupObjectklookupMapping::(Showk,Eqk,FailureObjectExtractErrorm)=>k->[(k,Objectkv)]->m[(k,Objectkv)]lookupMappingk=fromMapping<=<lookupObjectk