Commits

Bryan O'Sullivan committed 7ce31a2

Add a TH example.

Comments (0)

Files changed (6)

examples/Demo.hs

-{-# LANGUAGE OverloadedStrings #-}
-
--- Simplest example of parsing and encoding JSON with Aeson.
-
--- Above, we enable OverloadedStrings to allow a literal string (e.g. "name")
--- to be automatically converted to Data.Text.
--- This is useful when using Aeson's functions such as (.:) which expect Text.
--- Without it we'd need to use pack.
-
-import Data.Aeson
-import qualified Data.Aeson.Types as T
-
-import Data.Attoparsec (parse, Result(..))
-import Data.Text (Text)
-import Control.Applicative ((<$>))
-import Control.Monad (mzero)
-import qualified Data.ByteString.Char8 as BS
--- Aeson's "encode" to JSON generates lazy bytestrings
-import qualified Data.ByteString.Lazy.Char8 as BSL
-
--- In main we'll parse a JSON message into a Msg and display that,
--- then we'll encode a different Msg as JSON, and display it.
-main ::IO ()
-main = do
-  print $ parseMsgFromString exampleJSONMessage
-  let reply = Msg "hello Aeson!"
-  putStrLn $ "Encoded reply: " ++ BSL.unpack (encode reply)
-
--- this is the type we'll be converting to and from JSON
-data Msg = Msg Text deriving (Show)
-
--- here's how we should parse JSON and construct a Msg
-instance FromJSON Msg where
-  parseJSON (Object v) = Msg <$> v .: "message"
-  parseJSON _ = mzero
-
--- here's how we should encode a Msg as JSON
-instance ToJSON Msg where
-  toJSON (Msg s) = object [ "message" .= s]
-
--- Here's one way to actually run the parsers.
---
--- Note that we do two parses:
--- once into JSON then one more into our final type.
--- There are a number of choices when dealing with parse failures.
--- Here we've chosen to parse to Maybe Msg, and a Nothing will be returned
--- if parseJSON fails.  (More informative options are available.)
---
--- This should take us (depending on success or failure)
--- from {"message": "hello world"} to Just (Msg "hello world")
---                              or to Nothing
---
--- Note also that we have not checked here that the input has been completely
--- consumed, so:
--- {"message": "hello world"} foo BIG mistake
--- would yield the same successfully translated message!
--- We could look in "rest" for the remainder.
-parseMsgFromString :: String -> Maybe Msg
-parseMsgFromString s =
-  let bs = BS.pack s
-  in case parse json bs of
-       (Done rest r) -> T.parseMaybe parseJSON r :: Maybe Msg
-       _             -> Nothing
-
--- Here's the example JSON message we're going to try to parse:
--- {"message": "hello world"}
--- It's a JSON object with a single pair, having key 'message', and a string value.
--- It could have more fields and structure, but that's all we're going to parse out of it.
-exampleJSONMessage :: String
-exampleJSONMessage = "{\"message\":\"hello world\"}"

examples/Generic.hs

 instance FromJSON Coord
 instance ToJSON Coord
 
-main ::IO ()
+main :: IO ()
 main = do
   let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
   print req

examples/GenericSYB.hs

 data Coord = Coord { x :: Double, y :: Double }
              deriving (Show, Typeable, Data)
 
-main ::IO ()
+main :: IO ()
 main = do
   let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
   print req

examples/Simplest.hs

                          v .: "y"
   parseJSON _          = empty
 
-main ::IO ()
+main :: IO ()
 main = do
   let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
   print req

examples/TemplateHaskell.hs

+-- We can use Template Haskell (TH) to generate instances of the
+-- FromJSON and ToJSON classes automatically.  This is the fastest way
+-- to add JSON support for a type.
+
+{-# LANGUAGE TemplateHaskell #-}
+
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.Aeson (decode, encode)
+import Data.Aeson.TH (deriveJSON)
+import qualified Data.ByteString.Lazy.Char8 as BL
+
+data Coord = Coord { x :: Double, y :: Double }
+             deriving (Show)
+
+-- This splice will derive instances of ToJSON and FromJSON for us.
+--
+-- The use of "id" below is a placeholder function to transform the
+-- names of the type's fields.  We don't want to transform them, so we
+-- use the identity function.
+
+$(deriveJSON id ''Coord)
+
+main :: IO ()
+main = do
+  let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
+  print req
+  let reply = Coord 123.4 20
+  BL.putStrLn (encode reply)

release-notes.markdown

 # 0.3 to 0.4
 
+## Ease of use
+
+The new [`decode`
+function](http://hackage.haskell.org/packages/archive/aeson/latest/doc/html/Data-Aeson.html#v:decode)
+complements the longstanding `encode` function, and makes the API
+simpler.
+
+[New examples](https://github.com/bos/aeson/tree/master/examples) make
+it easier to learn to use the package.
+
+
 ## Generics support
 
-Aeson's support for data-type generic programming makes it possible to
+aeson's support for data-type generic programming makes it possible to
 use JSON encodings of most data types without writing any boilerplate
 instances.
 
 Thanks to Bas Van Dijk, aeson now supports the two major schemes for
 doing datatype-generic programming:
 
-* the newer mechanism, [built into GHC
+* the modern mechanism, [built into GHC
   itself](http://www.haskell.org/ghc/docs/latest/html/users_guide/generic-programming.html)
 
-* the older mechanism, based on SYB (for "scrap your boilerplate")
+* the older mechanism, based on SYB (aka "scrap your boilerplate")
 
-The GHC-based generics are fast and terse: in fact, they're generally
-comparable in performance to hand-written `ToJSON` and `FromJSON`
-instances.  To see how to use GHC generics, see
+The modern GHC-based generic mechanism is fast and terse: in fact, its
+performance is generally comparable in performance to hand-written and
+TH-derived `ToJSON` and `FromJSON` instances.  To see how to use GHC
+generics, refer to
 [`examples/Generic.hs`](https://github.com/bos/aeson/blob/master/examples/Generic.hs).
 
 The SYB-based generics support lives in
-[Data.Aeson.Generic](http://hackage.haskell.org/packages/archive/aeson/0.4.0.0/doc/html/Data-Aeson-Generic.html),
-and is provided mainly for users of GHC older than 7.2.  It's far
+[Data.Aeson.Generic](http://hackage.haskell.org/packages/archive/aeson/latest/doc/html/Data-Aeson-Generic.html),
+and is provided mainly for users of GHC older than 7.2.  SYB is far
 slower (by about 10x) than the more modern generic mechanism.  To see
-how to use SYB generics, see
+how to use SYB generics, refer to
 [`examples/GenericSYB.hs`](https://github.com/bos/aeson/blob/master/examples/GenericSYB.hs).
+
+
+## Improved performance
+
+* We switched the intermediate representation of JSON objects from
+  `Data.Map` to
+  [`Data.HashMap`](http://hackage.haskell.org/package/unordered-containers),
+  which has improved type conversion performance.
+
+* Instances of `ToJSON` and `FromJSON` for tuples are between 45% and
+  70% faster than in 0.3.