on master help sign in
Add a TH example.
commit4666c3b1ed37e5b1f7c08d1c1d01203ded68e1dd authorBryan O'Sullivan <bos@serpentine.com> dateWed 30 Nov 2011, 20:22 (15 years ago) parenteb3e4d3
6 files changed+64−82
examples/Demo.hs−70 examples/Generic.hs+1−1 examples/GenericSYB.hs+1−1 examples/Simplest.hs+1−1 examples/TemplateHaskell.hs+29 release-notes.markdown+32−9
examples/Demo.hsdeleted−70
@@ -1,70 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−
3−-- Simplest example of parsing and encoding JSON with Aeson.
4−
5−-- Above, we enable OverloadedStrings to allow a literal string (e.g. "name")
6−-- to be automatically converted to Data.Text.
7−-- This is useful when using Aeson's functions such as (.:) which expect Text.
8−-- Without it we'd need to use pack.
9−
10−import Data.Aeson
11−import qualified Data.Aeson.Types as T
12−
13−import Data.Attoparsec (parse, Result(..))
14−import Data.Text (Text)
15−import Control.Applicative ((<$>))
16−import Control.Monad (mzero)
17−import qualified Data.ByteString.Char8 as BS
18−-- Aeson's "encode" to JSON generates lazy bytestrings
19−import qualified Data.ByteString.Lazy.Char8 as BSL
20−
21−-- In main we'll parse a JSON message into a Msg and display that,
22−-- then we'll encode a different Msg as JSON, and display it.
23−main ::IO ()
24−main = do
25− print $ parseMsgFromString exampleJSONMessage
26− let reply = Msg "hello Aeson!"
27− putStrLn $ "Encoded reply: " ++ BSL.unpack (encode reply)
28−
29−-- this is the type we'll be converting to and from JSON
30−data Msg = Msg Text deriving (Show)
31−
32−-- here's how we should parse JSON and construct a Msg
33−instance FromJSON Msg where
34− parseJSON (Object v) = Msg <$> v .: "message"
35− parseJSON _ = mzero
36−
37−-- here's how we should encode a Msg as JSON
38−instance ToJSON Msg where
39− toJSON (Msg s) = object [ "message" .= s]
40−
41−-- Here's one way to actually run the parsers.
42−--
43−-- Note that we do two parses:
44−-- once into JSON then one more into our final type.
45−-- There are a number of choices when dealing with parse failures.
46−-- Here we've chosen to parse to Maybe Msg, and a Nothing will be returned
47−-- if parseJSON fails. (More informative options are available.)
48−--
49−-- This should take us (depending on success or failure)
50−-- from {"message": "hello world"} to Just (Msg "hello world")
51−-- or to Nothing
52−--
53−-- Note also that we have not checked here that the input has been completely
54−-- consumed, so:
55−-- {"message": "hello world"} foo BIG mistake
56−-- would yield the same successfully translated message!
57−-- We could look in "rest" for the remainder.
58−parseMsgFromString :: String -> Maybe Msg
59−parseMsgFromString s =
60− let bs = BS.pack s
61− in case parse json bs of
62− (Done rest r) -> T.parseMaybe parseJSON r :: Maybe Msg
63− _ -> Nothing
64−
65−-- Here's the example JSON message we're going to try to parse:
66−-- {"message": "hello world"}
67−-- It's a JSON object with a single pair, having key 'message', and a string value.
68−-- It could have more fields and structure, but that's all we're going to parse out of it.
69−exampleJSONMessage :: String
70−exampleJSONMessage = "{\"message\":\"hello world\"}"
examples/Generic.hs+1−1
@@ -30,7 +30,7 @@ data Coord = Coord { x :: Double, y :: Double }
3030instance FromJSON Coord
3131instance ToJSON Coord
3232
33−main ::IO ()
33+main :: IO ()
3434main = do
3535 let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
3636 print req
examples/GenericSYB.hs+1−1
@@ -22,7 +22,7 @@ import qualified Data.ByteString.Lazy.Char8 as BL
2222data Coord = Coord { x :: Double, y :: Double }
2323 deriving (Show, Typeable, Data)
2424
25−main ::IO ()
25+main :: IO ()
2626main = do
2727 let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
2828 print req
examples/Simplest.hs+1−1
@@ -22,7 +22,7 @@ instance FromJSON Coord where
2222 v .: "y"
2323 parseJSON _ = empty
2424
25−main ::IO ()
25+main :: IO ()
2626main = do
2727 let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
2828 print req
examples/TemplateHaskell.hsnew file+29
@@ -0,0 +1,29 @@
1+-- We can use Template Haskell (TH) to generate instances of the
2+-- FromJSON and ToJSON classes automatically. This is the fastest way
3+-- to add JSON support for a type.
4+
5+{-# LANGUAGE TemplateHaskell #-}
6+
7+{-# LANGUAGE OverloadedStrings #-}
8+
9+import Data.Aeson (decode, encode)
10+import Data.Aeson.TH (deriveJSON)
11+import qualified Data.ByteString.Lazy.Char8 as BL
12+
13+data Coord = Coord { x :: Double, y :: Double }
14+ deriving (Show)
15+
16+-- This splice will derive instances of ToJSON and FromJSON for us.
17+--
18+-- The use of "id" below is a placeholder function to transform the
19+-- names of the type's fields. We don't want to transform them, so we
20+-- use the identity function.
21+
22+$(deriveJSON id ''Coord)
23+
24+main :: IO ()
25+main = do
26+ let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
27+ print req
28+ let reply = Coord 123.4 20
29+ BL.putStrLn (encode reply)
release-notes.markdown+32−9
@@ -1,27 +1,50 @@
11# 0.3 to 0.4
22
3+## Ease of use
4+
5+The new [`decode`
6+function](http://hackage.haskell.org/packages/archive/aeson/latest/doc/html/Data-Aeson.html#v:decode)
7+complements the longstanding `encode` function, and makes the API
8+simpler.
9+
10+[New examples](https://github.com/bos/aeson/tree/master/examples) make
11+it easier to learn to use the package.
12+
13+
314## Generics support
415
5−Aeson's support for data-type generic programming makes it possible to
16+aeson's support for data-type generic programming makes it possible to
617use JSON encodings of most data types without writing any boilerplate
718instances.
819
920Thanks to Bas Van Dijk, aeson now supports the two major schemes for
1021doing datatype-generic programming:
1122
12−* the newer mechanism, [built into GHC
23+* the modern mechanism, [built into GHC
1324 itself](http://www.haskell.org/ghc/docs/latest/html/users_guide/generic-programming.html)
1425
15−* the older mechanism, based on SYB (for "scrap your boilerplate")
26+* the older mechanism, based on SYB (aka "scrap your boilerplate")
1627
17−The GHC-based generics are fast and terse: in fact, they're generally
18−comparable in performance to hand-written `ToJSON` and `FromJSON`
19−instances. To see how to use GHC generics, see
28+The modern GHC-based generic mechanism is fast and terse: in fact, its
29+performance is generally comparable in performance to hand-written and
30+TH-derived `ToJSON` and `FromJSON` instances. To see how to use GHC
31+generics, refer to
2032[`examples/Generic.hs`](https://github.com/bos/aeson/blob/master/examples/Generic.hs).
2133
2234The SYB-based generics support lives in
23−[Data.Aeson.Generic](http://hackage.haskell.org/packages/archive/aeson/0.4.0.0/doc/html/Data-Aeson-Generic.html),
24−and is provided mainly for users of GHC older than 7.2. It's far
35+[Data.Aeson.Generic](http://hackage.haskell.org/packages/archive/aeson/latest/doc/html/Data-Aeson-Generic.html),
36+and is provided mainly for users of GHC older than 7.2. SYB is far
2537slower (by about 10x) than the more modern generic mechanism. To see
26−how to use SYB generics, see
38+how to use SYB generics, refer to
2739[`examples/GenericSYB.hs`](https://github.com/bos/aeson/blob/master/examples/GenericSYB.hs).
40+
41+
42+## Improved performance
43+
44+* We switched the intermediate representation of JSON objects from
45+ `Data.Map` to
46+ [`Data.HashMap`](http://hackage.haskell.org/package/unordered-containers),
47+ which has improved type conversion performance.
48+
49+* Instances of `ToJSON` and `FromJSON` for tuples are between 45% and
50+ 70% faster than in 0.3.