on master help sign in
Merge pull request #525 from Lysxia/comments
13ee589Adam Bergmark
Data/Aeson/Types/FromJSON.hs+45−37
@@ -281,12 +281,12 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
281--
281--
282-- The basic ways to signal a failed conversion are as follows:
282-- The basic ways to signal a failed conversion are as follows:
283--
283--
284−-- * 'empty' and 'mzero' work, but are terse and uninformative
284+-- * 'empty' and 'mzero' work, but are terse and uninformative;
285--
285--
286−-- * 'fail' yields a custom error message
286+-- * 'fail' yields a custom error message;
287--
287--
288-- * 'typeMismatch' produces an informative message for cases when the
288-- * 'typeMismatch' produces an informative message for cases when the
289−-- value encountered is not of the expected type
289+-- value encountered is not of the expected type.
290--
290--
291-- An example type and instance using 'typeMismatch':
291-- An example type and instance using 'typeMismatch':
292--
292--
@@ -296,27 +296,27 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
296--
296--
297-- data Coord = Coord { x :: Double, y :: Double }
297-- data Coord = Coord { x :: Double, y :: Double }
298--
298--
299−-- instance FromJSON Coord where
299+-- instance 'FromJSON' Coord where
300−-- parseJSON ('Object' v) = Coord
300+-- 'parseJSON' ('Object' v) = Coord
301−-- '<$>' v '.:' \"x\"
301+-- '<$>' v '.:' \"x\"
302-- '<*>' v '.:' \"y\"
302-- '<*>' v '.:' \"y\"
303--
303--
304-- \-- We do not expect a non-'Object' value here.
304-- \-- We do not expect a non-'Object' value here.
305-- \-- We could use 'mzero' to fail, but 'typeMismatch'
305-- \-- We could use 'mzero' to fail, but 'typeMismatch'
306-- \-- gives a much more informative error message.
306-- \-- gives a much more informative error message.
307−-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid
307+-- 'parseJSON' invalid = 'typeMismatch' \"Coord\" invalid
308-- @
308-- @
309--
309--
310-- For this common case of only being concerned with a single
310-- For this common case of only being concerned with a single
311−-- type of JSON value, the functions @withObject@, @withNumber@, etc.
311+-- type of JSON value, the functions 'withObject', 'withNumber', etc.
312-- are provided. Their use is to be preferred when possible, since
312-- are provided. Their use is to be preferred when possible, since
313−-- they are more terse. Using @withObject@, we can rewrite the above instance
313+-- they are more terse. Using 'withObject', we can rewrite the above instance
314-- (assuming the same language extension and data type) as:
314-- (assuming the same language extension and data type) as:
315--
315--
316-- @
316-- @
317−-- instance FromJSON Coord where
317+-- instance 'FromJSON' Coord where
318−-- parseJSON = withObject \"Coord\" $ \v -> Coord
318+-- 'parseJSON' = 'withObject' \"Coord\" $ \v -> Coord
319−-- '<$>' v '.:' \"x\"
319+-- '<$>' v '.:' \"x\"
320-- '<*>' v '.:' \"y\"
320-- '<*>' v '.:' \"y\"
321-- @
321-- @
322--
322--
@@ -325,7 +325,7 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
325--
325--
326-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
326-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
327-- instance at compile time. The generated instance is optimized for your type
327-- instance at compile time. The generated instance is optimized for your type
328−-- so will probably be more efficient than the following two options:
328+-- so it will probably be more efficient than the following option.
329--
329--
330-- * The compiler can provide a default generic implementation for
330-- * The compiler can provide a default generic implementation for
331-- 'parseJSON'.
331-- 'parseJSON'.
@@ -343,18 +343,21 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
343--
343--
344-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
344-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
345--
345--
346−-- instance FromJSON Coord
346+-- instance 'FromJSON' Coord
347-- @
347-- @
348--
348--
349−-- If @DefaultSignatures@ doesn't give exactly the results you want,
349+-- The default implementation will be equivalent to
350+-- @parseJSON = 'genericParseJSON' 'defaultOptions'@; If you need different
350−-- you can customize the generic decoding with only a tiny amount of
351+-- options, you can customize the generic decoding by defining:
351−-- effort, using 'genericParseJSON' with your preferred 'Options':
352--
352--
353-- @
353-- @
354+-- customOptions = 'defaultOptions'
355+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
356+-- }
357+--
354−-- instance FromJSON Coord where
358+-- instance 'FromJSON' Coord where
355−-- parseJSON = 'genericParseJSON' 'defaultOptions'
359+-- 'parseJSON' = 'genericParseJSON' customOptions
356-- @
360-- @
357−
358class FromJSON a where
361class FromJSON a where
359 parseJSON :: Value -> Parser a
362 parseJSON :: Value -> Parser a
360
363
@@ -516,7 +519,7 @@ typeMismatch expected actual =
516--
519--
517-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
520-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
518-- instance at compile time. The generated instance is optimized for your type
521-- instance at compile time. The generated instance is optimized for your type
519−-- so will probably be more efficient than the following two options:
522+-- so it will probably be more efficient than the following option.
520--
523--
521-- * The compiler can provide a default generic implementation for
524-- * The compiler can provide a default generic implementation for
522-- 'liftParseJSON'.
525-- 'liftParseJSON'.
@@ -534,16 +537,20 @@ typeMismatch expected actual =
534--
537--
535-- data Pair a b = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
538-- data Pair a b = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
536--
539--
537−-- instance FromJSON a => FromJSON1 (Pair a)
540+-- instance 'FromJSON' a => 'FromJSON1' (Pair a)
538-- @
541-- @
539--
542--
540−-- If @DefaultSignatures@ doesn't give exactly the results you want,
543+-- If the default implementation doesn't give exactly the results you want,
541-- you can customize the generic decoding with only a tiny amount of
544-- you can customize the generic decoding with only a tiny amount of
542-- effort, using 'genericLiftParseJSON' with your preferred 'Options':
545-- effort, using 'genericLiftParseJSON' with your preferred 'Options':
543--
546--
544-- @
547-- @
548+-- customOptions = 'defaultOptions'
549+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
550+-- }
551+--
545−-- instance FromJSON a => FromJSON1 (Pair a) where
552+-- instance 'FromJSON' a => 'FromJSON1' (Pair a) where
546−-- liftParseJSON = 'genericLiftParseJSON' 'defaultOptions'
553+-- 'liftParseJSON' = 'genericLiftParseJSON' customOptions
547-- @
554-- @
548class FromJSON1 f where
555class FromJSON1 f where
549 liftParseJSON :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
556 liftParseJSON :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
@@ -614,43 +621,44 @@ instance (FromJSON a) => FromJSON [a] where
614-- Functions
621-- Functions
615-------------------------------------------------------------------------------
622-------------------------------------------------------------------------------
616
623
617−-- | @withObject expected f value@ applies @f@ to the 'Object' when @value@ is an @Object@
624+-- | @'withObject' expected f value@ applies @f@ to the 'Object' when @value@
618−-- and fails using @'typeMismatch' expected@ otherwise.
625+-- is an 'Object' and fails using @'typeMismatch' expected@ otherwise.
619withObject :: String -> (Object -> Parser a) -> Value -> Parser a
626withObject :: String -> (Object -> Parser a) -> Value -> Parser a
620withObject _ f (Object obj) = f obj
627withObject _ f (Object obj) = f obj
621withObject expected _ v = typeMismatch expected v
628withObject expected _ v = typeMismatch expected v
622{-# INLINE withObject #-}
629{-# INLINE withObject #-}
623
630
624−-- | @withText expected f value@ applies @f@ to the 'Text' when @value@ is a @String@
631+-- | @'withText' expected f value@ applies @f@ to the 'Text' when @value@ is a
625−-- and fails using @'typeMismatch' expected@ otherwise.
632+-- 'String' and fails using @'typeMismatch' expected@ otherwise.
626withText :: String -> (Text -> Parser a) -> Value -> Parser a
633withText :: String -> (Text -> Parser a) -> Value -> Parser a
627withText _ f (String txt) = f txt
634withText _ f (String txt) = f txt
628withText expected _ v = typeMismatch expected v
635withText expected _ v = typeMismatch expected v
629{-# INLINE withText #-}
636{-# INLINE withText #-}
630
637
631−-- | @withArray expected f value@ applies @f@ to the 'Array' when @value@ is an @Array@
638+-- | @'withArray' expected f value@ applies @f@ to the 'Array' when @value@ is
632−-- and fails using @'typeMismatch' expected@ otherwise.
639+-- an 'Array' and fails using @'typeMismatch' expected@ otherwise.
633withArray :: String -> (Array -> Parser a) -> Value -> Parser a
640withArray :: String -> (Array -> Parser a) -> Value -> Parser a
634withArray _ f (Array arr) = f arr
641withArray _ f (Array arr) = f arr
635withArray expected _ v = typeMismatch expected v
642withArray expected _ v = typeMismatch expected v
636{-# INLINE withArray #-}
643{-# INLINE withArray #-}
637
644
638−-- | @withNumber expected f value@ applies @f@ to the 'Number' when @value@ is a 'Number'.
645+-- | @'withNumber' expected f value@ applies @f@ to the 'Number' when @value@
639−-- and fails using @'typeMismatch' expected@ otherwise.
646+-- is a 'Number' and fails using @'typeMismatch' expected@ otherwise.
640withNumber :: String -> (Number -> Parser a) -> Value -> Parser a
647withNumber :: String -> (Number -> Parser a) -> Value -> Parser a
641withNumber expected f = withScientific expected (f . scientificToNumber)
648withNumber expected f = withScientific expected (f . scientificToNumber)
642{-# INLINE withNumber #-}
649{-# INLINE withNumber #-}
643{-# DEPRECATED withNumber "Use withScientific instead" #-}
650{-# DEPRECATED withNumber "Use withScientific instead" #-}
644
651
645−-- | @withScientific expected f value@ applies @f@ to the 'Scientific' number when @value@ is a 'Number'.
652+-- | @'withScientific' expected f value@ applies @f@ to the 'Scientific' number
646−-- and fails using @'typeMismatch' expected@ otherwise.
653+-- when @value@ is a 'Number' and fails using @'typeMismatch' expected@
654+-- otherwise.
647withScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
655withScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
648withScientific _ f (Number scientific) = f scientific
656withScientific _ f (Number scientific) = f scientific
649withScientific expected _ v = typeMismatch expected v
657withScientific expected _ v = typeMismatch expected v
650{-# INLINE withScientific #-}
658{-# INLINE withScientific #-}
651
659
652−-- | @withBool expected f value@ applies @f@ to the 'Bool' when @value@ is a @Bool@
660+-- | @'withBool' expected f value@ applies @f@ to the 'Bool' when @value@ is a
653−-- and fails using @'typeMismatch' expected@ otherwise.
661+-- 'Bool' and fails using @'typeMismatch' expected@ otherwise.
654withBool :: String -> (Bool -> Parser a) -> Value -> Parser a
662withBool :: String -> (Bool -> Parser a) -> Value -> Parser a
655withBool _ f (Bool arr) = f arr
663withBool _ f (Bool arr) = f arr
656withBool expected _ v = typeMismatch expected v
664withBool expected _ v = typeMismatch expected v
Data/Aeson/Types/ToJSON.hs+55−37
@@ -205,6 +205,9 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
205
205
206-- | A type that can be converted to JSON.
206-- | A type that can be converted to JSON.
207--
207--
208+-- Instances in general /must/ specify 'toJSON' and /should/ (but don't need
209+-- to) specify 'toEncoding'.
210+--
208-- An example type and instance:
211-- An example type and instance:
209--
212--
210-- @
213-- @
@@ -213,10 +216,10 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
213--
216--
214-- data Coord = Coord { x :: Double, y :: Double }
217-- data Coord = Coord { x :: Double, y :: Double }
215--
218--
216−-- instance ToJSON Coord where
219+-- instance 'ToJSON' Coord where
217−-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
220+-- 'toJSON' (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
218--
221--
219−-- toEncoding (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
222+-- 'toEncoding' (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
220-- @
223-- @
221--
224--
222-- Instead of manually writing your 'ToJSON' instance, there are two options
225-- Instead of manually writing your 'ToJSON' instance, there are two options
@@ -224,17 +227,15 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
224--
227--
225-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
228-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
226-- instance at compile time. The generated instance is optimized for your type
229-- instance at compile time. The generated instance is optimized for your type
227−-- so will probably be more efficient than the following two options:
230+-- so it will probably be more efficient than the following option.
228--
231--
229-- * The compiler can provide a default generic implementation for
232-- * The compiler can provide a default generic implementation for
230-- 'toJSON'.
233-- 'toJSON'.
231--
234--
232-- To use the second, simply add a @deriving 'Generic'@ clause to your
235-- To use the second, simply add a @deriving 'Generic'@ clause to your
233−-- datatype and declare a 'ToJSON' instance for your datatype without giving
236+-- datatype and declare a 'ToJSON' instance. If you require nothing other than
234−-- definitions for 'toJSON' or 'toEncoding'.
237+-- 'defaultOptions', it is sufficient to write (and this is the only
235−--
238+-- alternative where the default 'toJSON' implementation is sufficient):
236−-- For example, the previous example can be simplified to a more
237−-- minimal instance:
238--
239--
239-- @
240-- @
240-- {-\# LANGUAGE DeriveGeneric \#-}
241-- {-\# LANGUAGE DeriveGeneric \#-}
@@ -243,30 +244,41 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
243--
244--
244-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
245-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
245--
246--
246−-- instance ToJSON Coord where
247+-- instance 'ToJSON' Coord where
247−-- toEncoding = 'genericToEncoding' 'defaultOptions'
248+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
248-- @
249-- @
249--
250--
250−-- Why do we provide an implementation for 'toEncoding' here? The
251+-- If on the other hand you wish to customize the generic decoding, you have
251−-- 'toEncoding' function is a relatively new addition to this class.
252+-- to implement both methods:
252−-- To allow users of older versions of this library to upgrade without
253−-- having to edit all of their instances or encounter surprising
254−-- incompatibilities, the default implementation of 'toEncoding' uses
255−-- 'toJSON'. This produces correct results, but since it performs an
256−-- intermediate conversion to a 'Value', it will be less efficient
257−-- than directly emitting an 'Encoding'. Our one-liner definition of
258−-- 'toEncoding' above bypasses the intermediate 'Value'.
259−--
260−-- If @DefaultSignatures@ doesn't give exactly the results you want,
261−-- you can customize the generic encoding with only a tiny amount of
262−-- effort, using 'genericToJSON' and 'genericToEncoding' with your
263−-- preferred 'Options':
264--
253--
265-- @
254-- @
255+-- customOptions = 'defaultOptions'
256+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
257+-- }
258+--
266−-- instance ToJSON Coord where
259+-- instance 'ToJSON' Coord where
267−-- toJSON = 'genericToJSON' 'defaultOptions'
260+-- 'toJSON' = 'genericToJSON' customOptions
268−-- toEncoding = 'genericToEncoding' 'defaultOptions'
261+-- 'toEncoding' = 'genericToEncoding' customOptions
269-- @
262-- @
263+--
264+-- Previous versions of this library only had the 'toJSON' method. Adding
265+-- 'toEncoding' had to reasons:
266+--
267+-- 1. toEncoding is more efficient for the common case that the output of
268+-- 'toJSON' is directly serialized to a @ByteString@.
269+-- Further, expressing either method in terms of the other would be
270+-- non-optimal.
271+--
272+-- 2. The choice of defaults allows a smooth transition for existing users:
273+-- Existing instances that do not define 'toEncoding' still
274+-- compile and have the correct semantics. This is ensured by making
275+-- the default implementation of 'toEncoding' use 'toJSON'. This produces
276+-- correct results, but since it performs an intermediate conversion to a
277+-- 'Value', it will be less efficient than directly emitting an 'Encoding'.
278+-- (this also means that specifying nothing more than
279+-- @instance ToJSON Coord@ would be sufficient as a generically decoding
280+-- instance, but there probably exists no good reason to not specify
281+-- 'toEncoding' in new instances.)
270class ToJSON a where
282class ToJSON a where
271 -- | Convert a Haskell value to a JSON-friendly intermediate type.
283 -- | Convert a Haskell value to a JSON-friendly intermediate type.
272 toJSON :: a -> Value
284 toJSON :: a -> Value
@@ -288,8 +300,8 @@ class ToJSON a where
288 -- extension, and then have GHC generate a method body as follows.
300 -- extension, and then have GHC generate a method body as follows.
289 --
301 --
290 -- @
302 -- @
291− -- instance ToJSON Coord where
303+ -- instance 'ToJSON' Coord where
292− -- toEncoding = 'genericToEncoding' 'defaultOptions'
304+ -- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
293 -- @
305 -- @
294
306
295 toEncoding :: a -> Encoding
307 toEncoding :: a -> Encoding
@@ -491,7 +503,7 @@ contramapToJSONKeyFunction h x = case x of
491--
503--
492-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
504-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
493-- instance at compile time. The generated instance is optimized for your type
505-- instance at compile time. The generated instance is optimized for your type
494−-- so will probably be more efficient than the following two options:
506+-- so it will probably be more efficient than the following option.
495--
507--
496-- * The compiler can provide a default generic implementation for
508-- * The compiler can provide a default generic implementation for
497-- 'toJSON1'.
509-- 'toJSON1'.
@@ -509,19 +521,25 @@ contramapToJSONKeyFunction h x = case x of
509--
521--
510-- data Pair = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
522-- data Pair = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
511--
523--
512−-- instance ToJSON a => ToJSON1 (Pair a)
524+-- instance 'ToJSON' a => 'ToJSON1' (Pair a)
513-- @
525-- @
514--
526--
515−-- If @DefaultSignatures@ doesn't give exactly the results you want,
527+-- If the default implementation doesn't give exactly the results you want,
516-- you can customize the generic encoding with only a tiny amount of
528-- you can customize the generic encoding with only a tiny amount of
517-- effort, using 'genericLiftToJSON' and 'genericLiftToEncoding' with
529-- effort, using 'genericLiftToJSON' and 'genericLiftToEncoding' with
518-- your preferred 'Options':
530-- your preferred 'Options':
519--
531--
520-- @
532-- @
533+-- customOptions = 'defaultOptions'
534+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
535+-- }
536+--
521−-- instance ToJSON a => ToJSON1 (Pair a) where
537+-- instance 'ToJSON' a => 'ToJSON1' (Pair a) where
522−-- liftToJSON = 'genericLiftToJSON' 'defaultOptions'
538+-- 'liftToJSON' = 'genericLiftToJSON' customOptions
523−-- liftToEncoding = 'genericLiftToEncoding' 'defaultOptions'
539+-- 'liftToEncoding' = 'genericLiftToEncoding' customOptions
524-- @
540-- @
541+--
542+-- See also 'ToJSON'.
525class ToJSON1 f where
543class ToJSON1 f where
526 liftToJSON :: (a -> Value) -> ([a] -> Value) -> f a -> Value
544 liftToJSON :: (a -> Value) -> ([a] -> Value) -> f a -> Value
527
545
@@ -588,7 +606,7 @@ toEncoding2 = liftToEncoding2 toEncoding toEncodingList toEncoding toEncodingLis
588-- @
606-- @
589-- newtype F a = F [a]
607-- newtype F a = F [a]
590--
608--
591−-- -- This instance encodes String as an array of chars
609+-- -- This instance encodes 'String' as an array of chars
592-- instance 'ToJSON1' F where
610-- instance 'ToJSON1' F where
593-- 'liftToJSON' tj _ (F xs) = 'liftToJSON' tj ('listValue' tj) xs
611-- 'liftToJSON' tj _ (F xs) = 'liftToJSON' tj ('listValue' tj) xs
594-- 'liftToEncoding' te _ (F xs) = 'liftToEncoding' te ('listEncoding' te) xs
612-- 'liftToEncoding' te _ (F xs) = 'liftToEncoding' te ('listEncoding' te) xs