Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Quite frequently you will find yourself needing to convert between a rich semantic Haskell data type and a textual representation of that type which we call the external representation of a value. The external representation of the value is authoriative and is meant to be re-readable even in the face of changing implemetations on the program side.
Note that externalizing is not quite the same as serializing. If you have more complex data structures (ie rich types or nesting) then a simple text string will probably not be sufficient to convey sufficient information to represent it accurately. Serializing is focused on both performance encoding and decoding, and efficiency of the representation when transmitted over the wire. Of course, the obvious benefits of efficiency didn't stop the entire computer industry from near universal adoption of JSON as an interchange format, so there is, perhaps, no hope for us.
You can, however, regain some of your sanity by ensuring that the individual fields of a larger structure are safe, and that's where the externalizing machinery in this module comes in.
If you have read this far and think we are describing something similar to
Haskell's Show
, Python's repr()
or Java's toString()
you would be
correct, but at the level of primative and simple types we are providing the
ability to marshall them to a clean UTF-8 representation and to unmarshall
them back into Haskell values again.
The other major use case for this module is as a helper to read user input;
see queryOptionValue'
for an example that makes use of
this.
Notes for implementators
Postel's dictum to "be conservative in what you produce but liberal in what
you accept" describes the intent of this module. If you are implementing an
instance of Externalize
then you might consider being flexible as possible
when parsing with parseExternal
, within the constraints of having to read a
given value with exact fidelity. But when outputing a value with
formatExternal
you should be correcting the representation of the value to a
canonical, stable form, even if the original input was written differently.
See the discussion of creating Time
types from varying
inputs for an example.
Synopsis
- class Externalize ξ where
- formatExternal :: ξ -> Rope
- parseExternal :: Rope -> Maybe ξ
Documentation
class Externalize ξ where Source #
Convert between the internal Haskell representation of a data type and an external, textual form suitable for visualization, onward transmission, or archival storage.
It is expected that a valid instance of Externalize
allows you to round-trip
through it:
>>>
formatExternal (42 :: Int))
"42"
>>>
fromJust (parseExternal "42") :: Int
42
with the usual caveat about needing to ensure you've given enough information to the type-checker to know which instance you're asking for.
There is a general implementatation that goes though Show
and Read
via
String
but if you know you have a direct way to render or parse a type into
a sequence of characters then you can offer an instance of Externalize
which
does so more efficiently.
Since: 0.3.4
formatExternal :: ξ -> Rope Source #
Convert a value into an authoritative, stable textual representation for use externally.
parseExternal :: Rope -> Maybe ξ Source #
Attempt to read an external textual representation into a Haskell value.
Instances
Externalize Int16 Source # | Integers are represented in decimal: 42 |
Defined in Core.Encoding.External | |
Externalize Int32 Source # | Integers are represented in decimal: 42 |
Defined in Core.Encoding.External | |
Externalize Int64 Source # | Integers are represented in decimal: 42 |
Defined in Core.Encoding.External | |
Externalize Int8 Source # | Integers are represented in decimal: 42 |
Defined in Core.Encoding.External | |
Externalize Word16 Source # | Words are likewise represented in decimal: 65535 |
Defined in Core.Encoding.External | |
Externalize Word32 Source # | Words are likewise represented in decimal: 4294967295 |
Defined in Core.Encoding.External | |
Externalize Word64 Source # | Words are likewise represented in decimal: 18446744073709551615 |
Defined in Core.Encoding.External | |
Externalize Word8 Source # | Words are likewise represented in decimal: 255 |
Defined in Core.Encoding.External | |
Externalize Time Source # | Timestamps are formatted as per ISO 8601: 2022-06-20T14:51:23.544826062Z |
Defined in Core.Encoding.External | |
Externalize Rope Source # | |
Defined in Core.Encoding.External | |
Externalize Scientific Source # | Numbers are converted to scientific notation: 2.99792458e8 |
Defined in Core.Encoding.External formatExternal :: Scientific -> Rope Source # parseExternal :: Rope -> Maybe Scientific Source # | |
Externalize Day Source # | Days are formatted as per ISO 8601: 2022-06-20 |
Defined in Core.Encoding.External | |
Externalize UUID Source # | Unique identifiers are formatted as per RFC 4122: 6937e157-d041-4919-8690-4d6c12b7e0e3 |
Defined in Core.Encoding.External | |
Externalize String Source # | |
Defined in Core.Encoding.External | |
Externalize Double Source # | IEEE 754 floating point: 3.141592653589793 |
Defined in Core.Encoding.External | |
Externalize Float Source # | IEEE 754 floating point: 3.1415927 |
Defined in Core.Encoding.External | |
Externalize Int Source # | Integers are represented in decimal: 42 |
Defined in Core.Encoding.External | |
(Read a, Show a) => Externalize a Source # | |
Defined in Core.Encoding.External formatExternal :: a -> Rope Source # parseExternal :: Rope -> Maybe a Source # |