on master help sign in
Update the documentation of Serialize and Unbox
e7bb4d0Harendra Kumar
core/src/Streamly/Data/Serialize.hs+36−17
@@ -5,10 +5,43 @@
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
6-- Portability : GHC
6-- Portability : GHC
7--
7--
8+-- Fast binary serialization and deserialization of Haskell values to and from
9+-- arrays. This module provides two type classes for serialization, 'Unbox' and
10+-- 'Serialize'. The speed is similar to, and in some cases many times faster
11+-- than the store package. Conceptually, the 'Serialize' type class works in
12+-- the same way as store.
13+--
14+-- == Using Unbox
15+--
16+-- The 'Unbox' type class is simple and used to serialize non-recursive fixed
17+-- size data types. This type class is primarily used to implement unboxed
18+-- arrays. Unboxed arrays are just serialization of fixed length Haskell data
19+-- types. Instances of this type class can be derived using 'Generic' or
20+-- template haskell based deriving functions provided in this module. Read the
21+-- type class documentation for more details.
22+--
23+-- Writing a data type to an array using the array creation routines in
24+-- "Streamly.Data.Array" or "Streamly.Data.MutArray", serializes the type to
25+-- the array. Similarly, reading the data type from the array deserializes it.
26+--
27+-- There are no encode/decode routines provided to serialize or deserialize
28+-- using this type class but you can write those easily. Just create a mutable
29+-- byte array and use 'pokeByteIndex' to serialize a type, and use
30+-- 'peekByteIndex' to deserialize it.
31+--
32+-- == Using Serialize
33+--
34+-- The 'Serialize' type class is a superset of the 'Unbox' type class, it can
35+-- serialize variable length data types as well e.g. Haskell lists. Use
36+-- 'deriveSerialize' to derive the instances of the type class automatically
37+-- and then use 'pinnedEncode', 'decode' to serialize and deserialize the type
38+-- respectively. You can also create the array yourself and use the type class
39+-- functions directly.
40+--
8module Streamly.Data.Serialize
41module Streamly.Data.Serialize
9 (
42 (
10
43
11− -- * Types
44+ -- * MutableByteArray
12 MutableByteArray
45 MutableByteArray
13
46
14 -- * Unbox
47 -- * Unbox
@@ -18,14 +51,14 @@ module Streamly.Data.Serialize
18
51
19 -- * Serialize
52 -- * Serialize
20 , Serialize(..)
53 , Serialize(..)
54+ -- XXX Need to export the config setters as well.
55+ , defaultConfig
21 , deriveSerialize
56 , deriveSerialize
22 , deriveSerializeWith
57 , deriveSerializeWith
23
58
24− -- * Encoding
25 -- , encode
59 -- , encode
26 , pinnedEncode
60 , pinnedEncode
27
61
28− -- * Decoding
29 , decode
62 , decode
30 ) where
63 ) where
31
64
@@ -34,17 +67,3 @@ module Streamly.Data.Serialize
34--------------------------------------------------------------------------------
67--------------------------------------------------------------------------------
35
68
36import Streamly.Internal.Data.Serialize
69import Streamly.Internal.Data.Serialize
37− ( Serialize(..)
38− , decode
39− -- , encode
40− , pinnedEncode
41− )
42−import Streamly.Internal.Data.Serialize.TH
43− ( deriveSerialize
44− , deriveSerializeWith
45− )
46−import Streamly.Internal.Data.Unbox
47− ( MutableByteArray
48− , Unbox(..)
49− )
50−import Streamly.Internal.Data.Unbox.TH (deriveUnbox, deriveUnboxWith)
core/src/Streamly/Internal/Data/Serialize/TH.hs+19−11
@@ -426,13 +426,18 @@ deriveSerializeInternal conf headTy cons next = do
426 let methods = concat [sizeDec, peekDec, pokeDec]
426 let methods = concat [sizeDec, peekDec, pokeDec]
427 next methods
427 next methods
428
428
429−-- | Similar to 'deriveSerialize' but take a 'Config' to control how the
429+-- | @deriveSerializeWith config instance-dec@ generates a template Haskell
430−-- instance is generated.
430+-- splice consisting of a declaration of a 'Serialize' instance. @instance-dec@
431+-- is a template Haskell declaration splice consisting of a standard Haskell
432+-- instance declaration without the type class methods. The type class methods
433+-- for the given instance are generated according to the supplied @config@
434+-- parameter.
435+--
436+-- For example:
431--
437--
432−-- Usage:
433-- @
438-- @
434−-- $(deriveSerializeWith
439+-- \$(deriveSerializeWith
435−-- config
440+-- defaultConfig
436-- [d|instance Serialize a => Serialize (Maybe a)|])
441-- [d|instance Serialize a => Serialize (Maybe a)|])
437-- @
442-- @
438deriveSerializeWith :: Config -> Q [Dec] -> Q [Dec]
443deriveSerializeWith :: Config -> Q [Dec] -> Q [Dec]
@@ -478,23 +483,26 @@ deriveSerializeWith conf mDecs = do
478 go _ = errorMessage dec
483 go _ = errorMessage dec
479
484
480
485
481−-- | Template haskell helper to create instances of 'Serialize' automatically.
486+-- | @deriveSerialize dataTypeName@ generates a template Haskell splice
487+-- consisting of a declaration of the 'Serialize' instance for the given
488+-- dataTypeName, all type parameters of dataTypeName are required to have the
489+-- 'Serialize' constraint.
490+--
491+-- For example,
482--
492--
483−-- Consider the datatype:
484-- @
493-- @
485-- data CustomDataType a b c = ...
494-- data CustomDataType a b c = ...
495+-- \$(deriveSerialize ''CustomDataType)
486-- @
496-- @
487--
497--
488−-- Usage: @$(deriveSerialize ''CustomDataType)@
498+-- Generates the following code:
489--
499--
490−-- Note: All type variables automatcally get an "Serialize" constraint.
491−-- The derived code will look like the following,
492-- @
500-- @
493-- instance (Serialize a, Serialize b, Serialize c) => Serialize (CustomDataType a b c) where
501-- instance (Serialize a, Serialize b, Serialize c) => Serialize (CustomDataType a b c) where
494-- ...
502-- ...
495-- @
503-- @
496--
504--
497−-- To control which type variables don't get the Serialize constraint, use
505+-- To control which type parameters get the Serialize constraint, use
498-- 'deriveSerializeWith'.
506-- 'deriveSerializeWith'.
499deriveSerialize :: Name -> Q [Dec]
507deriveSerialize :: Name -> Q [Dec]
500deriveSerialize name = do
508deriveSerialize name = do
core/src/Streamly/Internal/Data/Serialize/Type.hs+57−21
@@ -61,21 +61,33 @@ import GHC.Exts
61-- Types
61-- Types
62--------------------------------------------------------------------------------
62--------------------------------------------------------------------------------
63
63
64−-- | A type implementing the 'Serialize' interface supplies operations for
64+-- | The 'Serialize' type class provides operations for serialization and
65−-- reading and writing the type from and to a mutable byte array (an unboxed
65+-- deserialization of general Haskell data types to and from their byte stream
66−-- representation of the type) in memory. The read operation 'deserialize'
66+-- representation.
67−-- deserializes the boxed type from the mutable byte array. The write operation
68−-- 'serialize' serializes the boxed type to the mutable byte array.
69--
67--
70−-- IMPORTANT: The serialized data's byte ordering is not normalized, which means
68+-- Unlike 'Unbox', 'Serialize' uses variable length encoding, therefore, it can
71−-- it remains the same as the machine's byte order where the function is
69+-- serialize recursive and variable length data types like lists, or variable
72−-- executed. Consequently, it may not be compatible across machines with
70+-- length sum types where the length of the value may vary depending on a
73−-- different byte ordering.
71+-- particular constructor. For variable length data types the length is encoded
72+-- along with the data.
74--
73--
75−-- 'Serialize' contains enough information to serialize and deserialize variable
74+-- The 'deserialize' operation reads bytes from the mutable byte array and
76−-- length types.
75+-- builds a Haskell data type from these bytes, the number of bytes it reads
76+-- depends on the type and the encoded value it is reading. 'serialize'
77+-- operation converts a Haskell data type to its binary representation which
78+-- must consist of as many bytes as returned by the @size@ operation on that
79+-- value and then stores these bytes into the mutable byte array. The
80+-- programmer is expected to use the @size@ operation and allocate an array of
81+-- sufficient length before calling 'serialize'.
77--
82--
78−-- >>> import Streamly.Internal.Data.Serialize.Type (Serialize(..))
83+-- IMPORTANT: The serialized data's byte ordering remains the same as the host
84+-- machine's byte order. Therefore, it can not be deserialized from host
85+-- machines with a different byte ordering.
86+--
87+-- Instances can be derived via Template Haskell, or written manually.
88+--
89+-- Here is an example, for deriving an instance of this type class using
90+-- template Haskell:
79--
91--
80-- >>> :{
92-- >>> :{
81-- data Object = Object
93-- data Object = Object
@@ -84,10 +96,24 @@ import GHC.Exts
84-- }
96-- }
85-- :}
97-- :}
86--
98--
99+-- @
100+-- import Streamly.Data.Serialize (deriveSerialize)
101+-- \$(deriveSerialize ''Object)
102+-- @
103+--
104+-- See 'Streamly.Data.Serialize.deriveSerialize' and
105+-- 'Streamly.Data.Serialize.deriveSerializeWith' for more information on
106+-- deriving using Template Haskell.
107+--
108+-- Here is an example of a manual instance.
109+--
110+-- >>> import Streamly.Data.Serialize (Serialize(..))
111+--
87-- >>> :{
112-- >>> :{
88-- instance Serialize Object where
113-- instance Serialize Object where
89-- size acc obj = size (size acc (_obj1 obj)) (_obj2 obj)
114-- size acc obj = size (size acc (_obj1 obj)) (_obj2 obj)
90-- deserialize i arr len = do
115-- deserialize i arr len = do
116+-- -- Check the array bounds before reading
91-- (i1, x0) <- deserialize i arr len
117-- (i1, x0) <- deserialize i arr len
92-- (i2, x1) <- deserialize i1 arr len
118-- (i2, x1) <- deserialize i1 arr len
93-- pure (i2, Object x0 x1)
119-- pure (i2, Object x0 x1)
@@ -104,23 +130,28 @@ class Serialize a where
104 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
130 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
105 -- traversal of the structures.
131 -- traversal of the structures.
106
132
107− -- | Get the size, in bytes, reqired to store the serialized
133+ -- | @size accum value@ returns @accum@ incremented by the size of the
108− -- representation of the type. Size cannot be zero.
134+ -- serialized representation of @value@ in bytes. Size cannot be zero. It
135+ -- should be at least 1 byte.
109 size :: Int -> a -> Int
136 size :: Int -> a -> Int
110
137
111 -- We can implement the following functions without returning the `Int`
138 -- We can implement the following functions without returning the `Int`
112 -- offset but that may require traversing the Haskell structure again to get
139 -- offset but that may require traversing the Haskell structure again to get
113 -- the size. Therefore, this is a performance optimization.
140 -- the size. Therefore, this is a performance optimization.
114
141
115− -- | @deserialize offset array arrayLen@ deserializes a value from the
142+ -- | @deserialize byte-offset array arrayLen@ deserializes a value from the
116− -- given byte-index in the array. Returns a tuple of the next byte-index
143+ -- given byte-offset in the array. Returns a tuple consisting of the next
117− -- and the deserialized value.
144+ -- byte-offset and the deserialized value.
145+ --
146+ -- Throws an exception if the operation would exceed the supplied arrayLen.
118 deserialize :: Int -> MutableByteArray -> Int -> IO (Int, a)
147 deserialize :: Int -> MutableByteArray -> Int -> IO (Int, a)
119
148
149+ -- | @serialize byte-offset array value@ writes the serialized
120− -- | Write the serialized representation of the value in the array at the
150+ -- representation of the @value@ in the array at the given byte-offset.
121− -- given byte-index. Returns the next byte-index. This is an unsafe
151+ -- Returns the next byte-offset.
152+ --
122− -- operation, the programmer must ensure that the array has enough space
153+ -- This is an unsafe operation, the programmer must ensure that the array
123− -- available in the array to serialize the value as determined by the
154+ -- has enough space available to serialize the value as determined by the
124 -- @size@ operation.
155 -- @size@ operation.
125 serialize :: Int -> MutableByteArray -> a -> IO Int
156 serialize :: Int -> MutableByteArray -> a -> IO Int
126
157
@@ -303,10 +334,15 @@ encodeAs ps a =
303encode :: Serialize a => a -> Array Word8
334encode :: Serialize a => a -> Array Word8
304encode = encodeAs Unpinned
335encode = encodeAs Unpinned
305
336
337+-- | Encode a Haskell type to a byte array. The array is allocated using pinned
338+-- memory so that it can be used directly in OS APIs for writing to file or
339+-- sending over the network.
306{-# INLINE pinnedEncode #-}
340{-# INLINE pinnedEncode #-}
307pinnedEncode :: Serialize a => a -> Array Word8
341pinnedEncode :: Serialize a => a -> Array Word8
308pinnedEncode = encodeAs Pinned
342pinnedEncode = encodeAs Pinned
309
343
344+-- | Decode a Haskell type from its serialized representation in a byte
345+-- array.
310{-# INLINE decode #-}
346{-# INLINE decode #-}
311decode :: Serialize a => Array Word8 -> a
347decode :: Serialize a => Array Word8 -> a
312decode arr@(Array {..}) = unsafeInlineIO $ do
348decode arr@(Array {..}) = unsafeInlineIO $ do
core/src/Streamly/Internal/Data/Unbox.hs+59−45
@@ -12,12 +12,17 @@
12-- Portability : GHC
12-- Portability : GHC
13--
13--
14module Streamly.Internal.Data.Unbox
14module Streamly.Internal.Data.Unbox
15− ( Unbox(..)
15+ (
16− , PinnedState(..)
16+ -- ** MutableByteArray
17− , MutableByteArray(..)
17+ MutableByteArray(..)
18− , touch
19 , getMutableByteArray#
18 , getMutableByteArray#
20 , sizeOfMutableByteArray
19 , sizeOfMutableByteArray
20+ , touch
21+ , nil
22+ , putSliceUnsafe
23+
24+ -- ** Allocation
25+ , PinnedState(..)
21 , isPinned
26 , isPinned
22 , pin
27 , pin
23 , unpin
28 , unpin
@@ -25,30 +30,29 @@ module Streamly.Internal.Data.Unbox
25 , newBytes
30 , newBytes
26 , pinnedNewBytes
31 , pinnedNewBytes
27 , pinnedNewAlignedBytes
32 , pinnedNewAlignedBytes
28− , nil
29− , putSliceUnsafe
30
33
31− -- * Type Parser and Builder
34+ -- ** Unbox type class
32− , BoundedPtr (..)
35+ , Unbox(..)
33
36
37+ -- ** Peek and poke utilities
38+ , BoundedPtr (..)
39+ -- Peek
34 , Peeker (..)
40 , Peeker (..)
35 , read
41 , read
36 , readUnsafe
42 , readUnsafe
37 , skipByte
43 , skipByte
38 , runPeeker
44 , runPeeker
39−
45+ -- Poke
40 , pokeBoundedPtrUnsafe
46 , pokeBoundedPtrUnsafe
41 , pokeBoundedPtr
47 , pokeBoundedPtr
42
48
43− -- * Generic Unbox instances
49+ -- ** Generic Deriving
44− , genericSizeOf
45− , genericPeekByteIndex
46− , genericPokeByteIndex
47−
48− -- Classess used for generic deriving.
49 , PeekRep(..)
50 , PeekRep(..)
50 , PokeRep(..)
51 , PokeRep(..)
51 , SizeOfRep(..)
52 , SizeOfRep(..)
53+ , genericSizeOf
54+ , genericPeekByteIndex
55+ , genericPokeByteIndex
52 ) where
56 ) where
53
57
54#include "MachDeps.h"
58#include "MachDeps.h"
@@ -92,6 +96,10 @@ data PinnedState
92 | Unpinned
96 | Unpinned
93
97
94-- XXX can use UnliftedNewtypes
98-- XXX can use UnliftedNewtypes
99+
100+-- | A lifted mutable byte array type wrapping @MutableByteArray# RealWorld@.
101+-- This is a low level array used to back high level unboxed arrays and
102+-- serialized data.
95data MutableByteArray = MutableByteArray (MutableByteArray# RealWorld)
103data MutableByteArray = MutableByteArray (MutableByteArray# RealWorld)
96
104
97{-# INLINE getMutableByteArray# #-}
105{-# INLINE getMutableByteArray# #-}
@@ -327,23 +335,37 @@ unpin arr@(MutableByteArray marr#) =
327-- size fields at each nesting level, aggregating the size upwards.
335-- size fields at each nesting level, aggregating the size upwards.
328
336
329-- | The 'Unbox' type class provides operations for serialization (unboxing)
337-- | The 'Unbox' type class provides operations for serialization (unboxing)
330−-- and deserialization (boxing) of a fixed-length, non-recursive Haskell data
338+-- and deserialization (boxing) of fixed-length, non-recursive Haskell data
331−-- type to and from its unboxed byte representation in a mutable byte array.
339+-- types to and from their byte stream representation.
340+--
332-- Unbox uses fixed size encoding, therefore, size is independent of the value,
341-- Unbox uses fixed size encoding, therefore, size is independent of the value,
333−-- it can be determined solely by the type. This makes types with 'Unbox'
342+-- it must be determined solely by the type. This restriction makes types with
334−-- instances suitable for storing in arrays. Note that sum types may have
343+-- 'Unbox' instances suitable for storing in arrays. Note that sum types may
335−-- multiple constructors of different sizes, the size of the sum type is
344+-- have multiple constructors of different sizes, the size of a sum type is
336-- computed as the maximum required by any constructor.
345-- computed as the maximum required by any constructor.
337--
346--
338−-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
347+-- The 'peekByteIndex' operation reads as many bytes from the mutable byte
339−-- representation stored in a mutable byte array, while the 'pokeByteIndex'
348+-- array as the @size@ of the data type and builds a Haskell data type from
340−-- write operation serializes a Haskell data type to its byte representation in
349+-- these bytes. 'pokeByteIndex' operation converts a Haskell data type to its
350+-- binary representation which consists of @size@ bytes and then stores
341−-- the mutable byte array. These operations do not check the bounds of the
351+-- these bytes into the mutable byte array. These operations do not check the
342−-- array, the user of the type class is expected to check the bounds before
352+-- bounds of the array, the user of the type class is expected to check the
343−-- peeking or poking.
353+-- bounds before peeking or poking.
354+--
355+-- IMPORTANT: The serialized data's byte ordering remains the same as the host
356+-- machine's byte order. Therefore, it can not be deserialized from host
357+-- machines with a different byte ordering.
344--
358--
345−-- Instances can be derived via Generics or Template Haskell. Note that the
359+-- Instances can be derived via Generics, Template Haskell, or written
346−-- data type must be non-recursive.
360+-- manually. Note that the data type must be non-recursive. WARNING! Generic
361+-- and Template Haskell deriving, both hang for recursive data types. Deriving
362+-- via Generics is more convenient but Template Haskell should be preferred
363+-- over Generics for the following reasons:
364+--
365+-- 1. Instances derived via Template Haskell provide better and more reliable
366+-- performance.
367+-- 2. Generic deriving allows only 256 fields or constructor tags whereas
368+-- template Haskell has no limit.
347--
369--
348-- Here is an example, for deriving an instance of this type class using
370-- Here is an example, for deriving an instance of this type class using
349-- generics:
371-- generics:
@@ -356,28 +378,20 @@ unpin arr@(MutableByteArray marr#) =
356-- } deriving Generic
378-- } deriving Generic
357-- :}
379-- :}
358--
380--
381+-- >>> import Streamly.Data.Serialize (Unbox(..))
382+-- >>> instance Unbox Object
383+--
359-- To derive the instance via Template Haskell:
384-- To derive the instance via Template Haskell:
360--
385--
361-- @
386-- @
362-- import Streamly.Data.Serialize (deriveUnbox)
387-- import Streamly.Data.Serialize (deriveUnbox)
363−-- $(deriveUnbox ''Object)
388+-- \$(deriveUnbox ''Object)
364-- @
389-- @
365--
390--
366-- See 'Streamly.Data.Serialize.deriveUnbox' and
391-- See 'Streamly.Data.Serialize.deriveUnbox' and
367-- 'Streamly.Data.Serialize.deriveUnboxWith' for more information on deriving
392-- 'Streamly.Data.Serialize.deriveUnboxWith' for more information on deriving
368-- using Template Haskell.
393-- using Template Haskell.
369--
394--
370−-- Deriving via Template Haskell should be preferred for the following reasons:
371−-- 1. Instances derived via Template Haskell have more performant routines.
372−-- 2. Template Haskell deriving can handle (maxBound :: Word64) number of
373−-- constructors whereas the Generic deriving can only handle 256.
374−--
375−-- WARNING! Generic and Template Haskell deriving, both hang for recursive data
376−-- types.
377−--
378−-- >>> import Streamly.Data.Array (Unbox(..))
379−-- >>> instance Unbox Object
380−--
381-- If you want to write the instance manually:
395-- If you want to write the instance manually:
382--
396--
383-- >>> :{
397-- >>> :{
@@ -395,15 +409,15 @@ unpin arr@(MutableByteArray marr#) =
395-- :}
409-- :}
396--
410--
397class Unbox a where
411class Unbox a where
398− -- | Get the size. Size cannot be zero.
412+ -- | Get the size. Size cannot be zero, should be at least 1 byte.
399 sizeOf :: Proxy a -> Int
413 sizeOf :: Proxy a -> Int
400
414
401 {-# INLINE sizeOf #-}
415 {-# INLINE sizeOf #-}
402 default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
416 default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
403 sizeOf = genericSizeOf
417 sizeOf = genericSizeOf
404
418
405− -- | Read an element of type "a" from a MutableByteArray given the byte
419+ -- | @peekByteIndex byte-index array@ reads an element of type @a@ from the
406− -- index.
420+ -- the given the byte index in the array.
407 --
421 --
408 -- IMPORTANT: The implementation of this interface may not check the bounds
422 -- IMPORTANT: The implementation of this interface may not check the bounds
409 -- of the array, the caller must not assume that.
423 -- of the array, the caller must not assume that.
@@ -414,8 +428,8 @@ class Unbox a where
414 Int -> MutableByteArray -> IO a
428 Int -> MutableByteArray -> IO a
415 peekByteIndex i arr = genericPeekByteIndex arr i
429 peekByteIndex i arr = genericPeekByteIndex arr i
416
430
417− -- | Write an element of type "a" to a MutableByteArray given the byte
431+ -- | @pokeByteIndex byte-index array@ writes an element of type @a@ to the
418− -- index.
432+ -- the given the byte index in the array.
419 --
433 --
420 -- IMPORTANT: The implementation of this interface may not check the bounds
434 -- IMPORTANT: The implementation of this interface may not check the bounds
421 -- of the array, the caller must not assume that.
435 -- of the array, the caller must not assume that.
core/src/Streamly/Internal/Data/Unbox/TH.hs+16−10
@@ -430,23 +430,25 @@ deriveUnboxInternal preds headTy cons = do
430 ]
430 ]
431 return [InstanceD Nothing preds (AppT (ConT ''Unbox) headTy) methods]
431 return [InstanceD Nothing preds (AppT (ConT ''Unbox) headTy) methods]
432
432
433−-- | Template haskell helper to create instances of 'Unbox' automatically.
433+-- | @deriveUnbox dataTypeName@ generates a template Haskell splice consisting
434+-- of a declaration of the 'Unbox' instance for the given dataTypeName, all type
435+-- parameters of dataTypeName are required to have the 'Unbox' constraint.
436+--
437+-- For example,
434--
438--
435−-- Consider the datatype:
436-- @
439-- @
437-- data CustomDataType a b c = ...
440-- data CustomDataType a b c = ...
441+-- \$(deriveUnbox ''CustomDataType)
438-- @
442-- @
439--
443--
440−-- Usage: @$(deriveUnbox ''CustomDataType)@
444+-- Generates the following code:
441--
445--
442−-- Note: All type variables automatcally get an "Unbox" constraint.
443−-- The derived code will look like the following,
444-- @
446-- @
445-- instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType a b c) where
447-- instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType a b c) where
446-- ...
448-- ...
447-- @
449-- @
448--
450--
449−-- To control which type variables get the Unbox constraint, use
451+-- To control which type parameters get the Unbox constraint, use
450-- 'deriveUnboxWith'.
452-- 'deriveUnboxWith'.
451deriveUnbox :: Name -> Q [Dec]
453deriveUnbox :: Name -> Q [Dec]
452deriveUnbox name = do
454deriveUnbox name = do
@@ -465,15 +467,19 @@ deriveUnbox name = do
465 ClassP ''Unbox [ty]
467 ClassP ''Unbox [ty]
466#endif
468#endif
467
469
468−-- | Like 'deriveUnbox' but control which type variables get the 'Unbox'
470+-- | @deriveUnbox dataTypeName@ generates a template Haskell splice consisting
471+-- of a declaration of the 'Unbox' instance for the given dataTypeName,
472+-- varNames is a list of parameter names of dataTypeName that are required
469−-- constraint.
473+-- to have the 'Unbox' constraint.
474+--
475+-- For example,
470--
476--
471−-- Consider the datatype:
472-- @
477-- @
473-- data CustomDataType a b c = ...
478-- data CustomDataType a b c = ...
479+-- \$(deriveUnboxWith ["a", "c"] ''CustomDataType)
474-- @
480-- @
475--
481--
476−-- Usage: @$(deriveUnboxWith ["a", "c"] ''CustomDataType)@
482+-- Generates the following code:
477--
483--
478-- @
484-- @
479-- instance (Unbox a, Unbox c) => Unbox (CustomDataType a b c) where
485-- instance (Unbox a, Unbox c) => Unbox (CustomDataType a b c) where