| 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
This package is typically used for debugging purposes. Hashed32 type
information keeps the size overhead relatively low, but requires a certain
amount of computational ressources. It is reliable at detecting errors, but
not very good at telling specifics about it. If a problem is identified, the
typing level can be increased to Shown or Full, providing information
about the involved types. If performance is critical, Untyped "typed"
encoding can be used, with minimal overhead compared to using Binary
directly.
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 =encodeTypedHashed32val dec =decodeTypedenc ::EitherStringBoolin
Using encodeTyped in particular has a significant advantage: when used to
create new specialized encoding functions, the type information has to be
calculated only once, and can be shared among further invocations of the
function. In other words, using
encodeInt ::Int->ByteStringencodeInt =encodeTypedHashed32
is much more efficient than
encodeInt ::Int->ByteStringencodeInt =encode.typedHashed32
since the latter recalculates the hash of "Int" on every invocation.
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)preserialize(compute serialized type representation and cache it, useful as an optimization)
Lastly, there are a number of encoding/decoding functions:
encodeTyped(pack inTypedand thenencode, but more efficient)decodeTyped(decodeTypedByteStringto)EitherStringadecodeTypedOrFail(likedecodeTyped, but with more meta information)unsafeDecodeTyped(which throws a runtime error on type mismatch)
(The Data.Binary.Typed.Debug module shares the same API.)