- data PropertyList
- data PartialPropertyList a
- data PropertyListS a
- data UnparsedPlistItem
- plArray :: PListAlgebra Identity a => [a] -> a
- fromPlArray :: PListCoalgebra Maybe a => a -> Maybe [a]
- plData :: PListAlgebra Identity a => ByteString -> a
- fromPlData :: PListCoalgebra Maybe a => a -> Maybe ByteString
- plDate :: PListAlgebra Identity a => UTCTime -> a
- fromPlDate :: PListCoalgebra Maybe a => a -> Maybe UTCTime
- plDict :: PListAlgebra Identity a => Map String a -> a
- fromPlDict :: PListCoalgebra Maybe a => a -> Maybe (Map String a)
- plReal :: PListAlgebra Identity a => Double -> a
- fromPlReal :: PListCoalgebra Maybe a => a -> Maybe Double
- plInt :: PListAlgebra Identity a => Integer -> a
- fromPlInt :: PListCoalgebra Maybe a => a -> Maybe Integer
- plString :: PListAlgebra Identity a => String -> a
- fromPlString :: PListCoalgebra Maybe a => a -> Maybe String
- plBool :: PListAlgebra Identity a => Bool -> a
- fromPlBool :: PListCoalgebra Maybe a => a -> Maybe Bool
- class Functor f => PListAlgebra f a
- class Functor f => PListCoalgebra f a
- class (PListAlgebra f a, PListCoalgebra f a) => InitialPList f a | f -> a, a -> f
- class (PListCoalgebra f a, PListAlgebra f a) => TerminalPList f a | f -> a, a -> f
- readPropertyList :: String -> Either String PropertyList
- showPropertyList :: PropertyList -> String
- readPropertyListFromFile :: FilePath -> IO PropertyList
- writePropertyListToFile :: FilePath -> PropertyList -> IO ()
- readXmlPropertyList :: FilePath -> Either String PropertyList
- showXmlPropertyList :: (InitialPList f pl, PListAlgebra f PlistItem) => pl -> String
- readXmlPropertyListFromFile :: FilePath -> IO PropertyList
- writeXmlPropertyListToFile :: (InitialPList f pl, PListAlgebra f PlistItem) => FilePath -> pl -> IO ()
- class PropertyListItem i where
- toPropertyList :: i -> PropertyList
- fromPropertyList :: PropertyList -> Maybe i
- listToPropertyList :: [i] -> PropertyList
- listFromPropertyList :: PropertyList -> Maybe [i]

- alterItemAtKeyPathM :: (Monad m, PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> m (Maybe i')) -> Maybe PropertyList -> m (Maybe PropertyList)
- alterItemAtKeyPath :: (PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> Maybe i') -> Maybe PropertyList -> Maybe PropertyList
- getItemAtKeyPath :: PropertyListItem i => [String] -> Maybe PropertyList -> Maybe i
- setItemAtKeyPath :: PropertyListItem i => [String] -> Maybe i -> Maybe PropertyList -> Maybe PropertyList

# The basic property list types

Property lists have several supported representations, but the main
one most end users will care about is `PropertyList`

. This is a basic
algebraic representation of property lists which can be constructed
using the polymorphic constructors described below and pattern-matched
using the polymorphic destructors (designed for convenient usage with
the ViewPatterns extension)

Also provided is the `PartialPropertyList`

representation, which is
a property list that is extended by adding a new constructor containing
some arbitrary type chosen by the user. It is mostly used as an
intermediate represenation for property lists that have been parsed
into their overall shape but not all elements have been parsed into
their final format.

The `UnparsedPlistItem`

type is the type most often used with
`PartialPropertyList`

, and that is really its only purpose - to
represent unparseable items from an XML plist during intermediate
stages of translation.

data PropertyList Source

A fully-parsed property list.

data PartialPropertyList a Source

A partially-parsed property-list term algebra, parameterized over the type of "structural holes" in the terms.

data PropertyListS a Source

The signature of the base property list algebra. This algebra is
"lifted" in various ways to support several different but similar
representations of property lists as well as projections and
injections. All the different representations are `connected`

through
this signature.

For example, `PropertyList`

is a fixed-point of this signature - that
is, a recursive version where `a`

is instantiated as

.
That gives the "expected" structure of a basic property list. It is both
initial and terminal for this signature in its 'un-lifted' form - which
is to say, any other type with an algebra for this signature (such as an
XML representation) can be made from a `PropertyListS`

a`PropertyList`

, and any type with
a coalgebra for this signature (such as a `String`

, an `Integer`

, etc.)
can be converted directly to a `PropertyList`

. This also means that any
transformation or series of transformations involving the `PropertyList`

type can be fused to "skip" generating intermediate property lists,
although there are currently no rewrite rules set up to do so.

Similarly, `PartialPropertyList`

is a fixed point of an arbitrarily-
augmented version of this signature (also known as the free monad
generated by the signature). Depending on its type parameter,
`PartialPropertyList`

can be terminal among many simple extensions to
the signature. Thus many types with a coalgebra for an extension of
this signature (such as XML given an appropriate tree destructor, or
the `PropertyList`

type itself) can be trivially converted to a
`PartialPropertyList`

.

PLArray [a] | |

PLData ByteString | |

PLDate UTCTime | |

PLDict (Map String a) | |

PLReal Double | |

PLInt Integer | |

PLString String | |

PLBool Bool |

Functor PropertyListS | |

Foldable PropertyListS | |

Traversable PropertyListS | |

MonadFree PropertyListS PartialPropertyList | |

Eq a => Eq (PropertyListS a) | |

Ord a => Ord (PropertyListS a) | |

Read a => Read (PropertyListS a) | |

Show a => Show (PropertyListS a) |

data UnparsedPlistItem Source

A representation of values that were structurally sound in the
property list file but the contents of which couldn't be interpreted
as what they claimed to be. The result of the initial parse phase will
typically be a `PartialPropertyList UnparsedPlistItem`

, and if
the whole plist was parsed properly will contain no actual values
of this type.

# Constructors and destructors for property lists

The "pl*" operations construct `PropertyList`

s, `PartialPropertyList`

s,
or any other types defining an unlifted algebra for the `PropertyListS`

signature.

The "fromPl*" operations are ViewPattern matching operations for
`PropertyList`

, `PartialPropertyList`

, or any other type defining
a `Maybe`

-lifted coalgebra for `PropertyListS`

.

The generality of these operations means that they can also be used
to directly generate or analyze "external" formats such as the XML
`Plist`

representation.

plArray :: PListAlgebra Identity a => [a] -> aSource

fromPlArray :: PListCoalgebra Maybe a => a -> Maybe [a]Source

plData :: PListAlgebra Identity a => ByteString -> aSource

fromPlData :: PListCoalgebra Maybe a => a -> Maybe ByteStringSource

plDate :: PListAlgebra Identity a => UTCTime -> aSource

fromPlDate :: PListCoalgebra Maybe a => a -> Maybe UTCTimeSource

fromPlDict :: PListCoalgebra Maybe a => a -> Maybe (Map String a)Source

plReal :: PListAlgebra Identity a => Double -> aSource

fromPlReal :: PListCoalgebra Maybe a => a -> Maybe DoubleSource

plInt :: PListAlgebra Identity a => Integer -> aSource

plString :: PListAlgebra Identity a => String -> aSource

fromPlString :: PListCoalgebra Maybe a => a -> Maybe StringSource

plBool :: PListAlgebra Identity a => Bool -> aSource

fromPlBool :: PListCoalgebra Maybe a => a -> Maybe BoolSource

# The internal algebraic model for property lists

Internally, conversions between various property list representations are all defined in terms of universal algebra, which is basically just fancy math-talk for "very general interfaces that let you convert between certain kinds of representations easily and efficiently".

Most users do not need to understand this stuff - the class names are only exported because they appear in the types of the constructors and destructors. For more detailed info, see Data.PropertyList.Algebra.

class Functor f => PListAlgebra f a Source

A class for types which can be constructed algebraically from the
`PropertyListS`

signature (lifted by `f`

) - in other words, types which
you can put property lists into.

The `f`

-lifting is provided to support extending the algebra. The algebra
is defined in a class rather than passing around functions because most of
the time for any given type there is only one algebra you care about.

Typically a renderer for an output format will be implemented as a type
with an `instance `

. For example, the XML
output system is implemented in the `PListAlgebra`

`Identity`

`instance `

.
`PListAlgebra`

`Identity`

`Data.PropertyList.Xml.Types.Plist`

Copointed f => PListAlgebra f PropertyList | |

Copointed f => PListAlgebra f PlistItem | |

PListAlgebra f PlistItem => PListAlgebra f Plist | |

Copointed f => PListAlgebra f (PartialPropertyList a) | |

PListAlgebra Maybe (PartialPropertyList ()) | |

PListCoalgebra Identity a => PListAlgebra (Either a) PropertyList | |

PListAlgebra (Either PlistItem) PlistItem | |

PListAlgebra (Either UnparsedPlistItem) PlistItem | |

PListAlgebra (Either a) (PartialPropertyList a) |

class Functor f => PListCoalgebra f a Source

A class for types which can be dissected (pattern-matched) into the
`PropertyListS`

signature (lifted by `f`

) - in other words, types which
you can take property lists out of.

Typically a property list parser will be implemented as a type with a
`PListCoalgebra`

instance, where `f`

is either `Identity`

in the case where
the parser guarantees to return a fully well-formed property list
(assuming it returns anything at all) or `Either`

`something`

when the
parser only guarantees that the structure is sound (but that some elements
might be defective, in which case a value of type `something`

would be
substituted). The XML parser, for example, is based on the latter
approach, where `something`

is `UnparsedPlistItem`

.

class (PListAlgebra f a, PListCoalgebra f a) => InitialPList f a | f -> a, a -> fSource

An identification of the fact that the type `a`

has an initial plist algebra
(under some lifting `f`

). Functional dependencies are in use - for any
type, only one of its initial algebras (if multiple apply, which they may
because the same type may be initial for multiple distinct liftings)
can be chosen, and for any lifting only one type's algebra may be chosen.
This is to make types decidable in the not-so-uncommon case where the
lifting is encapsulated (eg, any time `foldPList`

is partially applied
- for example, see the signature of `fromPlist`

).

For cases where the lifting either needs to be chosen or needs to be
transformed to another lifting, `fromPlistWith`

is provided. It is based
on the same definition as the default implementation of `foldPList`

but
also inserts a chosen transformation of the lifting.

Question for self: Is the PListCoalgebra context reasonable here?
Some rough calculations suggest that in the presence of fixed point
type operators, it is possible to construct a PListCoalgebra for any
InitialPList, which essentially is defined as pattern matching. So,
I'm not totally sure but I think this is reasonable - at least, for
finitary signatures, which we're using as long as `f`

doesn't go crazy.

class (PListCoalgebra f a, PListAlgebra f a) => TerminalPList f a | f -> a, a -> fSource

Chosen terminal coalgebra for the given lifting, and chosen lifting
for the given type. See also `InitialPList`

.

# Parsing and formatting property lists using any supported format

readPropertyList :: String -> Either String PropertyListSource

Read a property list from a `String`

, trying all supported property list formats.
Presently, only the "XML1" format is supported. See also `readXmlPropertyList`

.

showPropertyList :: PropertyList -> StringSource

Write a property list to a `String`

, using a "preferred" property list format.
Presently, that is the "XML1" format. See also `showXmlPropertyList`

.

readPropertyListFromFile :: FilePath -> IO PropertyListSource

Read a property list from a file, trying all supported property list formats.
Presently, only the "XML1" format is supported. See also
`readXmlPropertyListFromFile`

.

writePropertyListToFile :: FilePath -> PropertyList -> IO ()Source

Write a property list to a file, using a "preferred" property list format.
Presently, that is the "XML1" format. See also `writeXmlPropertyListToFile`

.

# Parsing and formatting property lists using the XML format

showXmlPropertyList :: (InitialPList f pl, PListAlgebra f PlistItem) => pl -> StringSource

Render a propertylist to a `String`

in the xml1 plist format from any
initial propertylist type (which includes `PropertyList`

,

, and `PartialPropertyList`

`UnparsedPlistItem`

).
`PartialPropertyList`

`PlistItem`

readXmlPropertyListFromFile :: FilePath -> IO PropertyListSource

Read a property list from a file in the xml1 format. If parsing fails,
calls `fail`

.

writeXmlPropertyListToFile :: (InitialPList f pl, PListAlgebra f PlistItem) => FilePath -> pl -> IO ()Source

Output a propertylist to a file in the xml1 plist format from any
initial propertylist type (which includes `PropertyList`

,

, and `PartialPropertyList`

`UnparsedPlistItem`

).
`PartialPropertyList`

`PlistItem`

# Manipulating property lists

This module exports a class (`PropertyListItem`

) and several functions
used to manipulate `PropertyList`

s and their contents at a high level,
viewing and manipulating the data in the tree through ad-hoc
transformations.

For example, consider the following property list:

myPlist = plDict $ M.fromList [ ("foo", plInt 4) , ("bar", plString "qux") , ("subDict", plDict $ M.fromList [ ("item 1", plString "This is item 1!") , ("item B", plBool True) ]) ] :: PropertyList

Some typical actions you might do with a plist like this (Note that
in many cases a `Just`

is added - this is because the key-path operations
are defined in terms of `Maybe`

so that operations like `setItemAtKeyPath`

or `alterItemAtKeyPath`

can create new items where none already exist):

getItemAtKeyPath ["subDict", "item B"] (Just myPlist) :: Maybe Bool

(returns `Just True`

)

getItemAtKeyPath ["subDict"] (Just myPlist) :: M.Map String String

(returns `M.fromList [("item 1", "This is item 1!"), ("item B", "YES")]`

.
Note the stringification of non-string items. In general, `PropertyListItem`

instances are expected to do "reasonable" conversions to try and make sense
of what the user is asking the system to do.)

setItemAtKeyPath ["omg", "lolwut"] (Just "roflcopter") (Just myPlist)

(returns a modified version of `myPlist`

with
```
plDict $ M.fromList [("omg", plDict $ M.fromList [("omg",
plDict $ M.fromList [("lolwut", plString "roflcopter")])])]
```

added to the root dictionary)

setItemAtKeyPath ["foo"] Nothing (Just myPlist)

(returns a modified version of `myPlist`

with the "foo" entry in the
root dictionary deleted)

setItemAtKeyPath ["foo", "bar", "baz"] (Just "qux") Nothing

(returns a new dictionary with `plString "qux"`

at the key path foo.bar.baz)

class PropertyListItem i whereSource

A class for items which can be converted to and from property lists. This
is more general than `PListAlgebra`

and `PListCoalgebra`

, in that it allows
for transformations that are not primitive-recursive. This relaxation is
necessary and desirable in the `PropertyListItem`

situation because we are
more interested in composable injection/projection operations on than in
universal maps.

The algebraic interface also cannot work for arrays or dictionaries,
because it only allows primitive (co-)recursion - the conversions can only
operate on one layer of `PropertyListS`

at a time. This could be
handled by enlarging the types (from [t] to Either t [t], for example)
or by encoding in-band (by taking a singleton list to be an element
instead of a list, for example), but both of those "solutions" create
headaches of their own, and in any case the algebraic interface is probably
too bizarre for most users.

toPropertyList :: i -> PropertyListSource

Construct a `PropertyList`

from the item.

fromPropertyList :: PropertyList -> Maybe iSource

Convert a property list to a property list item if its contents
_exactly_ fit the target type. Note that when using types
such as `Map`

`String`

`Int`

(as opposed to `Map`

`String`

`PropertyList`

) this will mean that a single element of the
dictionary of a non-`Int`

type will cause the entire conversion to
fail.

listToPropertyList :: [i] -> PropertyListSource

In order to support a general instance for lists without breaking String, we use the same trick as the Prelude uses for Show. Generally, the list methods should not be overridden, and maybe they shouldn't even be exported.

listFromPropertyList :: PropertyList -> Maybe [i]Source

alterItemAtKeyPathM :: (Monad m, PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> m (Maybe i')) -> Maybe PropertyList -> m (Maybe PropertyList)Source

`alterItemAtKeyPathM path f`

applies the function `f`

deep inside the
`PropertyList`

on the property list item at the given key-path `path`

(if possible). This is the same notion of key path as is used in the
Apple plist APIs - each component of the path indicates descending
into a dictionary by selecting the element with that key (if any). If a
key is not found, it is created. If a key is found but is not a
dictionary, the operation fails (with `fail`

from the `Monad`

class).

If the result of `f`

is `Nothing`

, and the resulting dictionary is empty,
that dictionary is deleted in the result (and any empty parent dictionaries).
If this is not the behavior you want, you should alter the parent dictionary
itself and return an empty one.

alterItemAtKeyPath :: (PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> Maybe i') -> Maybe PropertyList -> Maybe PropertyListSource

`alterItemAtKeyPath path f`

applies the function `f`

deep inside the
`PropertyList`

on the property list item at the given key-path `path`

(if possible). This is the same notion of key path as is used in the
Apple plist APIs - namely, each component of the path indicates descending
into a dictionary by selecting the element with that key (if any). If a
key is not found, it is created. If a key is found but is not a
dictionary, the operation fails (with `error`

).

If the result of `f`

is `Nothing`

, and the resulting dictionary is empty,
that dictionary is deleted in the result (and any empty parent dictionaries).
If this is not the behavior you want, you should alter the parent dictionary
itself and return an empty one.

getItemAtKeyPath :: PropertyListItem i => [String] -> Maybe PropertyList -> Maybe iSource

Gets the item, if any (and if convertible to the required type),
at a given key path. If the key path passes through something that
is not a dictionary, the operation returns `Nothing`

.

setItemAtKeyPath :: PropertyListItem i => [String] -> Maybe i -> Maybe PropertyList -> Maybe PropertyListSource

Sets the item at a given key-path. If the key path does not exist, it is
created. If it exists but passes through something that is not a dictionary,
the operation fails (with `error`

)