| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Data.Binary.Typed.Tutorial
Description
This meta-module exists only for documentational purposes; the library functionality is found in Data.Binary.Typed.
Motivation
Standard Binary serializes to ByteString, which
is an untyped format; deserialization of unexpected input usually results
in unusable data.
This module defines a Typed type, which allows serializing both a value
and the type of that value; deserialization can then check whether the
received data was sent assuming the right type, and error messages
may provide insight into the type mismatch.
For example, this uses Binary directly:
test1 = let val = 10 ::Intenc =encodeval dec =decodeenc ::Boolin
This behaves unexpectedly: An Int value is converted to a Bool, which
corresponds to a wacky type coercion. The receiving end has no way of
knowing what the incoming data should have been interpreted as.
Using Typed, this can be avoided:
test2 = let val = 10 ::Intenc =encode(typedFullval) dec =decodeenc ::TypedBoolin
This time decode raises an error: the incoming data is tagged
as an Int, but is attempted to be decoded as Bool.
Basic usage
For convenience, this module exports a couple of convenience functions that have the type-mangling baked in already. The above example could have been written as
test3 = let val = 10 ::Intenc =encodeTypedval dec =decodeTypedenc ::EitherStringBoolin
However, using encodeTyped is computationally inefficient when many
messages of the same type are serialized, since it recomputes a serialized
version of that type for every single serialized value from scratch.
encodeTypedLike exists to remedy that: it takes a separately constructed
Typed dummy value, and computes a new serialization function for that type
out of it. This serialization function then re-uses the type representation
of the dummy value, and simply replaces the contained value on each
serialization so that no unnecessary overhead is introduced.
-- ComputesInts type representation 100 times: manyIntsNaive = mapencodeTyped[1..100 ::Int] -- Much more efficient: prepare dummy value to precache the -- type representation, computing it only once:encodeInt=encodeTypedLike(typedFull(0 ::Int)) manyIntsCached = mapencodeInt[1..100]
API overview
The core definitions in Data.Binary.Typed are:
Typed(the main type)typed(constructTypedvalues)TypeFormat(a helper type fortyped)erase(deconstructTypedvales)
In addition to those, a couple of useful helper functions with more efficient implementation than what the core definitions could offer:
mapTyped(change values contained inTypeds)reValue(change value, but don't recompute type representation)reType(change type representation, but keep value)precache(compute serialized type representation, useful as an optimization)
Lastly, there are a number of encoding/decoding functions, mostly for convenience:
encodeTyped(pack inTypedand thenencode)encodeTypedLike(usually much more efficient version ofencodeTyped)decodeTyped(decodeTypedByteStringto)EitherStringadecodeTypedOrFail(likedecodeTyped, but with more meta information)unsafeDecodeTyped(which throws a runtime error on type mismatch)