on master help sign in
Merge pull request #425 from phadej/compose

Add Compose instances, correct Identity

commitb5af896452c1a4ed656b933db1059156de979037 authorAdam Bergmark <adam@bergmark.nl> dateMon 13 Jun 2016, 20:31 (10 years ago) parent6a983c6d7a4c3e
7 files changed+292−59
Data/Aeson/Types/FromJSON.hs+44−10 Data/Aeson/Types/ToJSON.hs+81−25 aeson.cabal+3−1 tests/Instances.hs+24−1 tests/Properties.hs+40 tests/Types.hs+6 tests/UnitTests.hs+94−22
Data/Aeson/Types/FromJSON.hs+44−10
@@ -82,6 +82,7 @@ import Control.Monad ((<=<))
8282import Data.Attoparsec.Number (Number (..))
8383import Data.Bits (unsafeShiftR)
8484import Data.Fixed (Fixed, HasResolution)
85+import Data.Functor.Compose (Compose (..))
8586import Data.Functor.Identity (Identity (..))
8687import Data.Hashable (Hashable (..))
8788import Data.Int (Int16, Int32, Int64, Int8)
@@ -961,13 +962,6 @@ notFound key = fail $ "The key \"" ++ unpack key ++ "\" was not found"
961962-- base
962963-------------------------------------------------------------------------------
963964
964−instance FromJSON1 Identity where
965− liftParseJSON p _ a = Identity <$> p a
966− {-# INLINE liftParseJSON #-}
967−
968−instance (FromJSON a) => FromJSON (Identity a) where
969− parseJSON = parseJSON1
970− {-# INLINE parseJSON #-}
971965
972966instance FromJSON2 Const where
973967 liftParseJSON2 p _ _ _ = fmap Const . p
@@ -1256,6 +1250,49 @@ instance (FromJSON a) => FromJSON (DList.DList a) where
12561250 parseJSON = parseJSON1
12571251 {-# INLINE parseJSON #-}
12581252
1253+-------------------------------------------------------------------------------
1254+-- tranformers - Functors
1255+-------------------------------------------------------------------------------
1256+
1257+instance FromJSON1 Identity where
1258+ liftParseJSON p _ a = Identity <$> p a
1259+ {-# INLINE liftParseJSON #-}
1260+
1261+ liftParseJSONList _ p a = fmap Identity <$> p a
1262+ {-# INLINE liftParseJSONList #-}
1263+
1264+instance (FromJSON a) => FromJSON (Identity a) where
1265+ parseJSON = parseJSON1
1266+ {-# INLINE parseJSON #-}
1267+
1268+ parseJSONList = liftParseJSONList parseJSON parseJSONList
1269+ {-# INLINE parseJSONList #-}
1270+
1271+instance (FromJSONKey a, FromJSON a) => FromJSONKey (Identity a) where
1272+ fromJSONKey = coerceFromJSONKeyFunction (fromJSONKey :: FromJSONKeyFunction a)
1273+ fromJSONKeyList = coerceFromJSONKeyFunction (fromJSONKeyList :: FromJSONKeyFunction [a])
1274+
1275+
1276+instance (FromJSON1 f, FromJSON1 g) => FromJSON1 (Compose f g) where
1277+ liftParseJSON p pl a = Compose <$> liftParseJSON g gl a
1278+ where
1279+ g = liftParseJSON p pl
1280+ gl = liftParseJSONList p pl
1281+ {-# INLINE liftParseJSON #-}
1282+
1283+ liftParseJSONList p pl a = map Compose <$> liftParseJSONList g gl a
1284+ where
1285+ g = liftParseJSON p pl
1286+ gl = liftParseJSONList p pl
1287+ {-# INLINE liftParseJSONList #-}
1288+
1289+instance (FromJSON1 f, FromJSON1 g, FromJSON a) => FromJSON (Compose f g a) where
1290+ parseJSON = parseJSON1
1291+ {-# INLINE parseJSON #-}
1292+
1293+ parseJSONList = liftParseJSONList parseJSON parseJSONList
1294+ {-# INLINE parseJSONList #-}
1295+
12591296-------------------------------------------------------------------------------
12601297-- containers
12611298-------------------------------------------------------------------------------
@@ -1514,9 +1551,6 @@ instance FromJSONKey Char where
15141551instance (FromJSONKey a, FromJSON a) => FromJSONKey [a] where
15151552 fromJSONKey = fromJSONKeyList
15161553
1517−instance (FromJSONKey a, FromJSON a) => FromJSONKey (Identity a) where
1518− fromJSONKey = mapFromJSONKeyFunction Identity fromJSONKey
1519−
15201554-------------------------------------------------------------------------------
15211555-- Tuple instances, see tuple-instances-from.hs
15221556-------------------------------------------------------------------------------
Data/Aeson/Types/ToJSON.hs+81−25
@@ -72,6 +72,7 @@ import Data.Bits (unsafeShiftR)
7272import Data.DList (DList)
7373import Data.Fixed (Fixed, HasResolution)
7474import Data.Foldable (toList)
75+import Data.Functor.Compose (Compose (..))
7576import Data.Functor.Identity (Identity (..))
7677import Data.Int (Int16, Int32, Int64, Int8)
7778import Data.List (intersperse)
@@ -305,7 +306,7 @@ instance KeyValue Pair where
305306
306307-- | Typeclass for types that can be used as the key of a map-like container
307308-- (like 'Map' or 'HashMap'). For example, since 'Text' has a 'ToJSONKey'
308−-- instance and 'Char' has a 'ToJSON' instance, we can encode a value of
309+-- instance and 'Char' has a 'ToJSON' instance, we can encode a value of
309310-- type 'Map' 'Text' 'Char':
310311--
311312-- >>> LBC8.putStrLn $ encode $ Map.fromList [("foo" :: Text, 'a')]
@@ -351,16 +352,16 @@ instance KeyValue Pair where
351352-- >>> let m = Map.fromList [(Foo 4 "bar",'a'),(Foo 6 "arg",'b')]
352353-- >>> LBC8.putStrLn $ encode m
353354-- [[{"fooName":"bar","fooAge":4},"a"],[{"fooName":"arg","fooAge":6},"b"]]
354−--
355+--
355356-- The next case to consider is if we have a type that is a
356357-- newtype wrapper around 'Text'. The recommended approach is to use
357358-- generalized newtype deriving:
358359--
359360-- > newtype RecordId = RecordId { getRecordId :: Text}
360361-- > deriving (Eq,Ord,ToJSONKey)
361−--
362+--
362363-- Then we may write:
363−--
364+--
364365-- >>> LBC8.putStrLn $ encode $ Map.fromList [(RecordId "abc",'a')]
365366-- {"abc":"a"}
366367--
@@ -378,7 +379,7 @@ instance KeyValue Pair where
378379-- > instance ToJSONKey Color where
379380-- > toJSONKey = ToJSONKeyText f g
380381-- > where f = Text.pack . show
381−-- > g = text . Text.pack . show
382+-- > g = text . Text.pack . show
382383-- > -- text function is from Data.Aeson.Encoding
383384--
384385-- The situation of needing to turning function @a -> Text@ into
@@ -387,7 +388,7 @@ instance KeyValue Pair where
387388--
388389-- > instance ToJSONKey Color where
389390-- > toJSONKey = toJSONKeyText (Text.pack . show)
390−--
391+--
391392-- The performance of the above instance can be improved by
392393-- not using 'String' as an intermediate step when converting to
393394-- 'Text'. One option for improving performance would be to use
@@ -396,7 +397,7 @@ instance KeyValue Pair where
396397-- builder) is generated by encoding the 'Text' to a 'ByteString',
397398-- an intermediate step that could be avoided. The fastest possible
398399-- implementation would be:
399−--
400+--
400401-- > -- Assuming that OverloadedStrings is enabled
401402-- > instance ToJSONKey Color where
402403-- > toJSONKey = ToJSONKeyText f g
@@ -1163,21 +1164,6 @@ instance ( GToEncoding arity a
11631164-- base
11641165-------------------------------------------------------------------------------
11651166
1166−instance ToJSON1 Identity where
1167− liftToJSON t _ (Identity a) = t a
1168− {-# INLINE liftToJSON #-}
1169−
1170− liftToEncoding t _ (Identity a) = t a
1171− {-# INLINE liftToEncoding #-}
1172−
1173−instance (ToJSON a) => ToJSON (Identity a) where
1174− toJSON = toJSON1
1175− {-# INLINE toJSON #-}
1176−
1177− toEncoding = toEncoding1
1178− {-# INLINE toEncoding #-}
1179−
1180−
11811167instance ToJSON2 Const where
11821168 liftToJSON2 t _ _ _ (Const x) = t x
11831169 {-# INLINE liftToJSON2 #-}
@@ -1574,6 +1560,79 @@ instance (ToJSON a) => ToJSON (DList.DList a) where
15741560 toEncoding = toEncoding1
15751561 {-# INLINE toEncoding #-}
15761562
1563+-------------------------------------------------------------------------------
1564+-- transformers - Functors
1565+-------------------------------------------------------------------------------
1566+
1567+instance ToJSON1 Identity where
1568+ liftToJSON t _ (Identity a) = t a
1569+ {-# INLINE liftToJSON #-}
1570+
1571+ liftToJSONList _ tl xs = tl (map runIdentity xs)
1572+ {-# INLINE liftToJSONList #-}
1573+
1574+ liftToEncoding t _ (Identity a) = t a
1575+ {-# INLINE liftToEncoding #-}
1576+
1577+ liftToEncodingList _ tl xs = tl (map runIdentity xs)
1578+ {-# INLINE liftToEncodingList #-}
1579+
1580+instance (ToJSON a) => ToJSON (Identity a) where
1581+ toJSON = toJSON1
1582+ {-# INLINE toJSON #-}
1583+
1584+ toJSONList = liftToJSONList toJSON toJSONList
1585+ {-# INLINE toJSONList #-}
1586+
1587+ toEncoding = toEncoding1
1588+ {-# INLINE toEncoding #-}
1589+
1590+ toEncodingList = liftToEncodingList toEncoding toEncodingList
1591+ {-# INLINE toEncodingList #-}
1592+
1593+instance (ToJSONKey a, ToJSON a) => ToJSONKey (Identity a) where
1594+ toJSONKey = contramapToJSONKeyFunction runIdentity toJSONKey
1595+ toJSONKeyList = contramapToJSONKeyFunction (map runIdentity) toJSONKeyList
1596+
1597+
1598+instance (ToJSON1 f, ToJSON1 g) => ToJSON1 (Compose f g) where
1599+ liftToJSON tv tvl (Compose x) = liftToJSON g gl x
1600+ where
1601+ g = liftToJSON tv tvl
1602+ gl = liftToJSONList tv tvl
1603+ {-# INLINE liftToJSON #-}
1604+
1605+ liftToJSONList te tel xs = liftToJSONList g gl (map getCompose xs)
1606+ where
1607+ g = liftToJSON te tel
1608+ gl = liftToJSONList te tel
1609+ {-# INLINE liftToJSONList #-}
1610+
1611+ liftToEncoding te tel (Compose x) = liftToEncoding g gl x
1612+ where
1613+ g = liftToEncoding te tel
1614+ gl = liftToEncodingList te tel
1615+ {-# INLINE liftToEncoding #-}
1616+
1617+ liftToEncodingList te tel xs = liftToEncodingList g gl (map getCompose xs)
1618+ where
1619+ g = liftToEncoding te tel
1620+ gl = liftToEncodingList te tel
1621+ {-# INLINE liftToEncodingList #-}
1622+
1623+instance (ToJSON1 f, ToJSON1 g, ToJSON a) => ToJSON (Compose f g a) where
1624+ toJSON = toJSON1
1625+ {-# INLINE toJSON #-}
1626+
1627+ toJSONList = liftToJSONList toJSON toJSONList
1628+ {-# INLINE toJSONList #-}
1629+
1630+ toEncoding = toEncoding1
1631+ {-# INLINE toEncoding #-}
1632+
1633+ toEncodingList = liftToEncodingList toEncoding toEncodingList
1634+ {-# INLINE toEncodingList #-}
1635+
15771636-------------------------------------------------------------------------------
15781637-- containers
15791638-------------------------------------------------------------------------------
@@ -1954,9 +2013,6 @@ instance ToJSONKey Char where
19542013instance (ToJSONKey a, ToJSON a) => ToJSONKey [a] where
19552014 toJSONKey = toJSONKeyList
19562015
1957−instance (ToJSONKey a, ToJSON a) => ToJSONKey (Identity a) where
1958− toJSONKey = contramapToJSONKeyFunction runIdentity toJSONKey
1959−
19602016-------------------------------------------------------------------------------
19612017-- Tuple instances, see tuple-instances-to.hs
19622018-------------------------------------------------------------------------------
aeson.cabal+3−1
@@ -174,7 +174,9 @@ test-suite tests
174174 quickcheck-instances >=0.3.12
175175
176176 if !impl(ghc >= 8.0)
177− build-depends: semigroups >= 0.16.1 && < 0.19
177+ build-depends:
178+ semigroups >= 0.16.1 && < 0.19,
179+ transformers >= 0.2.2.0
178180
179181 if !impl(ghc >= 7.10)
180182 build-depends: nats >=1 && <1.2
tests/Instances.hs+24−1
@@ -1,5 +1,6 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE OverloadedStrings #-}
45{-# LANGUAGE RecordWildCards #-}
56{-# LANGUAGE StandaloneDeriving #-}
@@ -23,8 +24,11 @@ import Data.Aeson.Types
2324import Control.Applicative (Const(..), empty)
2425import Data.Tagged (Tagged(..))
2526import Data.Proxy (Proxy(..))
27+import Data.Functor.Identity (Identity (..))
28+import Data.Functor.Compose (Compose (..))
2629import Functions
2730import qualified Data.DList as DList
31+import qualified Data.HashMap.Strict as HM
2832
2933import Data.Orphans ()
3034import Test.QuickCheck.Instances ()
@@ -57,8 +61,20 @@ instance ApproxEq UTCTime where
5761instance ApproxEq DotNetTime where
5862 (=~) = (=~) `on` fromDotNetTime
5963
64+instance ApproxEq Float where
65+ a =~ b
66+ | isNaN a && isNaN b = True
67+ | otherwise = approxEq a b
68+
6069instance ApproxEq Double where
61− (=~) = approxEq
70+ a =~ b
71+ | isNaN a && isNaN b = True
72+ | otherwise = approxEq a b
73+
74+instance (ApproxEq k, Eq v) => ApproxEq (HM.HashMap k v) where
75+ a =~ b = and $ zipWith eq (HM.toList a) (HM.toList b)
76+ where
77+ eq (x,y) (u,v) = x =~ u && y == v
6278
6379-- Test-related types.
6480
@@ -180,3 +196,10 @@ instance Arbitrary a => Arbitrary (Const a b) where
180196
181197instance Arbitrary a => Arbitrary (DList.DList a) where
182198 arbitrary = DList.fromList <$> arbitrary
199+
200+-- would like to have -- https://github.com/nick8325/quickcheck/issues/73
201+instance Arbitrary a => Arbitrary (Identity a) where
202+ arbitrary = Identity <$> arbitrary
203+
204+instance Arbitrary (f (g a)) => Arbitrary (Compose f g a) where
205+ arbitrary = Compose <$> arbitrary
tests/Properties.hs+40
@@ -1,5 +1,8 @@
11{-# LANGUAGE CPP, OverloadedStrings, ScopedTypeVariables #-}
22
3+-- For Arbitrary Compose
4+{-# LANGUAGE FlexibleContexts #-}
5+
36module Properties where
47
58import Prelude ()
@@ -16,6 +19,7 @@ import Data.Sequence (Seq)
1619import Data.DList (DList)
1720import Data.Hashable (Hashable)
1821import Data.HashMap.Strict (HashMap)
22+import Data.Functor.Compose (Compose (..))
1923import Data.Map (Map)
2024import Data.Ratio (Ratio)
2125import Data.List.NonEmpty (NonEmpty)
@@ -137,6 +141,7 @@ isObjectWithSingleField _ = False
137141
138142--------------------------------------------------------------------------------
139143
144+
140145tests :: Test
141146tests = testGroup "properties" [
142147 testGroup "encode" [
@@ -169,6 +174,41 @@ tests = testGroup "properties" [
169174 , testProperty "Seq" $ roundTripEq (undefined :: Seq Int)
170175 , testProperty "Rational" $ roundTripEq (undefined :: Rational)
171176 , testProperty "Ratio Int" $ roundTripEq (undefined :: Ratio Int)
177+ , testGroup "functors"
178+ [ testProperty "Identity Char" $ roundTripEq (undefined :: I Int)
179+
180+ , testProperty "Identity Char" $ roundTripEq (undefined :: I Char)
181+ , testProperty "Identity [Char]" $ roundTripEq (undefined :: I [Char])
182+ , testProperty "[Identity Char]" $ roundTripEq (undefined :: [I Char])
183+
184+ , testProperty "Compose I I Int" $ roundTripEq (undefined :: Compose I I Int)
185+ , testProperty "Compose [] I Int" $ roundTripEq (undefined :: Compose [] I Int)
186+ , testProperty "Compose I [] Int" $ roundTripEq (undefined :: Compose I [] Int)
187+ , testProperty "Compose [] [] Int" $ roundTripEq (undefined :: Compose [] [] Int)
188+
189+ , testProperty "Compose I I Char" $ roundTripEq (undefined :: Compose I I Char)
190+ , testProperty "Compose [] I Char" $ roundTripEq (undefined :: Compose [] I Char)
191+ , testProperty "Compose I [] Char" $ roundTripEq (undefined :: Compose I [] Char)
192+ , testProperty "Compose [] [] Char" $ roundTripEq (undefined :: Compose [] [] Char)
193+
194+ , testProperty "Compose3 I I I Char" $ roundTripEq (undefined :: Compose3 I I I Char)
195+ , testProperty "Compose3 I [] I Char" $ roundTripEq (undefined :: Compose3 I [] I Char)
196+ , testProperty "Compose3 I I [] Char" $ roundTripEq (undefined :: Compose3 I I [] Char)
197+ , testProperty "Compose3 I [] [] Char" $ roundTripEq (undefined :: Compose3 I [] [] Char)
198+ , testProperty "Compose3 [] I I Char" $ roundTripEq (undefined :: Compose3 [] I I Char)
199+ , testProperty "Compose3 [] [] I Char" $ roundTripEq (undefined :: Compose3 [] [] I Char)
200+ , testProperty "Compose3 [] I [] Char" $ roundTripEq (undefined :: Compose3 [] I [] Char)
201+ , testProperty "Compose3 [] [] [] Char" $ roundTripEq (undefined :: Compose3 [] [] [] Char)
202+
203+ , testProperty "Compose3' I I I Char" $ roundTripEq (undefined :: Compose3' I I I Char)
204+ , testProperty "Compose3' I [] I Char" $ roundTripEq (undefined :: Compose3' I [] I Char)
205+ , testProperty "Compose3' I I [] Char" $ roundTripEq (undefined :: Compose3' I I [] Char)
206+ , testProperty "Compose3' I [] [] Char" $ roundTripEq (undefined :: Compose3' I [] [] Char)
207+ , testProperty "Compose3' [] I I Char" $ roundTripEq (undefined :: Compose3' [] I I Char)
208+ , testProperty "Compose3' [] [] I Char" $ roundTripEq (undefined :: Compose3' [] [] I Char)
209+ , testProperty "Compose3' [] I [] Char" $ roundTripEq (undefined :: Compose3' [] I [] Char)
210+ , testProperty "Compose3' [] [] [] Char" $ roundTripEq (undefined :: Compose3' [] [] [] Char)
211+ ]
172212 , testGroup "ghcGenerics" [
173213 testProperty "OneConstructor" $ roundTripEq OneConstructor
174214 , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool)
tests/Types.hs+6
@@ -12,6 +12,12 @@ import Data.Data
1212import Data.Text
1313import GHC.Generics
1414import Test.QuickCheck (Property, counterexample)
15+import Data.Functor.Compose (Compose (..))
16+import Data.Functor.Identity (Identity (..))
17+
18+type I = Identity
19+type Compose3 f g h = Compose (Compose f g) h
20+type Compose3' f g h = Compose f (Compose g h)
1521
1622data Foo = Foo {
1723 fooInt :: Int
tests/UnitTests.hs+94−22
@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE CPP, GADTs, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
22#if __GLASGOW_HASKELL__ >= 708
33{-# LANGUAGE DataKinds #-}
44#endif
@@ -10,6 +10,9 @@ module UnitTests (ioTests, tests) where
1010import Prelude ()
1111import Prelude.Compat
1212
13+import Types (I, Compose3, Compose3', Approx(..))
14+import Instances ()
15+
1316import Control.Applicative (Const(..))
1417import Control.Monad (forM)
1518import Data.Aeson (FromJSONKeyFunction(..), FromJSONKey(..), decode, eitherDecode, encode, genericToJSON, genericToEncoding, object, FromJSON(..), withObject, (.=), (.:), (.:?), (.:!))
@@ -20,6 +23,8 @@ import Data.Aeson.Types (ToJSON(..), Value, camelTo, camelTo2, defaultOptions, o
2023import Data.Char (toUpper)
2124import Data.Hashable (hash)
2225import Data.List.NonEmpty (NonEmpty(..))
26+import Data.Functor.Compose (Compose (..))
27+import Data.Functor.Identity (Identity (..))
2328import Data.Maybe (fromMaybe)
2429import Data.Proxy (Proxy(..))
2530import Data.Sequence (Seq)
@@ -42,6 +47,7 @@ import qualified Data.Text.Lazy.Encoding as LT
4247import qualified Data.Sequence as Seq
4348import qualified Data.DList as DList
4449import qualified Data.HashMap.Strict as HM
50+import qualified Data.Map as M
4551
4652tests :: Test
4753tests = testGroup "unit" [
@@ -70,6 +76,7 @@ tests = testGroup "unit" [
7076 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
7177 , testGroup "To JSON representation" $ fmap (testCase "-") jsonEncoding
7278 , testGroup "From JSON representation" $ fmap (testCase "-") jsonDecoding
79+ , testGroup "To/From JSON representation" $ fmap assertJsonExample jsonExamples
7380 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
7481 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
7582 , testGroup "Issue #351" $ fmap (testCase "-") issue351
@@ -234,31 +241,96 @@ dotColonMark = [
234241-----------------------------------------------------------------------------
235242
236243jsonEncoding :: [Assertion]
237−jsonEncoding = [
238− assertEqual "Either Left" "{\"Left\":1}" $ encode (Left 1 :: Either Int Int)
239− , assertEqual "Either Right" "{\"Right\":1}" $ encode (Right 1 :: Either Int Int)
240− , assertEqual "Nothing" "null" $ encode (Nothing :: Maybe Int)
241− , assertEqual "Just" "1" $ encode (Just 1 :: Maybe Int)
242− , assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))
243− , assertEqual "Proxy Int" "null" $ encode (Proxy :: Proxy Int)
244− , assertEqual "Tagged Char Int" "1" $ encode (Tagged 1 :: Tagged Char Int)
244+jsonEncoding =
245+ [
246+ -- https://github.com/bos/aeson/issues/376
247+ assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))
248+ -- infinities cannot be recovered, null is decoded as NaN
249+ , assertEqual "inf :: Double" "null" $ encode (Approx $ 1/0 :: Approx Double)
250+ ]
251+
252+data Example where
253+ Example
254+ :: (Eq a, Show a, ToJSON a, FromJSON a)
255+ => String -> L.ByteString -> a -> Example
256+
257+assertJsonExample :: Example -> Test
258+assertJsonExample (Example name bs val) = testCase name $ do
259+ assertEqual "encode" bs (encode val)
260+ assertEqual "decode" (Just val) (decode bs)
261+
262+jsonExamples :: [Example]
263+jsonExamples =
264+ [
265+ Example "Either Left" "{\"Left\":1}" (Left 1 :: Either Int Int)
266+ , Example "Either Right" "{\"Right\":1}" (Right 1 :: Either Int Int)
267+ , Example "Nothing" "null" (Nothing :: Maybe Int)
268+ , Example "Just" "1" (Just 1 :: Maybe Int)
269+ , Example "Proxy Int" "null" (Proxy :: Proxy Int)
270+ , Example "Tagged Char Int" "1" (Tagged 1 :: Tagged Char Int)
245271#if __GLASGOW_HASKELL__ >= 708
246272 -- Test Tagged instance is polykinded
247− , assertEqual "Tagged 123 Int" "1" $ encode (Tagged 1 :: Tagged 123 Int)
273+ , Example "Tagged 123 Int" "1" (Tagged 1 :: Tagged 123 Int)
248274#endif
249− , assertEqual "Const Char Int" "\"c\"" $ encode (Const 'c' :: Const Char Int)
250− , assertEqual "Tuple" "[1,2]" $ encode ((1, 2) :: (Int, Int))
251− , assertEqual "NonEmpty" "[1,2,3]" $ encode (1 :| [2, 3] :: NonEmpty Int)
252− , assertEqual "Seq" "[1,2,3]" $ encode (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
253− , assertEqual "DList" "[1,2,3]" $ encode (DList.fromList [1, 2, 3] :: DList.DList Int)
254− , assertEqual "()" "[]" $ encode ()
255− , assertEqual "HashMap Int Int" "{\"0\":1,\"2\":3}" $ encode (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
256− , assertEqual "nan :: Double" "null" $ encode (0/0 :: Double)
257− , assertEqual "inf :: Double" "null" $ encode (1/0 :: Double)
275+ , Example "Const Char Int" "\"c\"" (Const 'c' :: Const Char Int)
276+ , Example "Tuple" "[1,2]" ((1, 2) :: (Int, Int))
277+ , Example "NonEmpty" "[1,2,3]" (1 :| [2, 3] :: NonEmpty Int)
278+ , Example "Seq" "[1,2,3]" (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
279+ , Example "DList" "[1,2,3]" (DList.fromList [1, 2, 3] :: DList.DList Int)
280+ , Example "()" "[]" ()
281+
282+ , Example "HashMap Int Int" "{\"0\":1,\"2\":3}" (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
283+ , Example "Map Int Int" "{\"0\":1,\"2\":3}" (M.fromList [(0,1),(2,3)] :: M.Map Int Int)
284+ , Example "Map (Tagged Int Int) Int" "{\"0\":1,\"2\":3}" (M.fromList [(Tagged 0,1),(Tagged 2,3)] :: M.Map (Tagged Int Int) Int)
285+ , Example "Map [Int] Int" "[[[0],1],[[2],3]]" (M.fromList [([0],1),([2],3)] :: M.Map [Int] Int)
286+ , Example "Map [Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [("ab",1),("cd",3)] :: M.Map [Char] Int)
287+ , Example "Map [I Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [(map pure "ab",1),(map pure "cd",3)] :: M.Map [I Char] Int)
288+
289+ , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
290+
258291 -- Three separate cases, as ordering in HashMap is not defined
259− , assertEqual "HashMap Float Int, NaN" "{\"NaN\":1}" $ encode (HM.singleton (0/0) 1 :: HM.HashMap Float Int)
260− , assertEqual "HashMap Float Int, Infinity" "{\"Infinity\":1}" $ encode (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
261− , assertEqual "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" $ encode (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
292+ , Example "HashMap Float Int, NaN" "{\"NaN\":1}" (Approx $ HM.singleton (0/0) 1 :: Approx (HM.HashMap Float Int))
293+ , Example "HashMap Float Int, Infinity" "{\"Infinity\":1}" (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
294+ , Example "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
295+
296+ -- Functors
297+ , Example "Identity Int" "1" (pure 1 :: Identity Int)
298+
299+ , Example "Identity Char" "\"x\"" (pure 'x' :: Identity Char)
300+ , Example "Identity String" "\"foo\"" (pure "foo" :: Identity String)
301+ , Example "[Identity Char]" "\"xy\"" ([pure 'x', pure 'y'] :: [Identity Char])
302+
303+ , Example "Maybe Char" "\"x\"" (pure 'x' :: Maybe Char)
304+ , Example "Maybe String" "\"foo\"" (pure "foo" :: Maybe String)
305+ , Example "Maybe [Identity Char]" "\"xy\"" (pure [pure 'x', pure 'y'] :: Maybe [Identity Char])
306+
307+ , Example "Compose I I Int" "1" (pure 1 :: Compose I I Int)
308+ , Example "Compose I [] Int" "[1]" (pure 1 :: Compose I [] Int)
309+ , Example "Compose [] I Int" "[1]" (pure 1 :: Compose [] I Int)
310+ , Example "Compose [] [] Int" "[[1]]" (pure 1 :: Compose [] [] Int)
311+
312+ , Example "Compose I I Char" "\"x\"" (pure 'x' :: Compose I I Char)
313+ , Example "Compose I [] Char" "\"x\"" (pure 'x' :: Compose I [] Char)
314+ , Example "Compose [] I Char" "\"x\"" (pure 'x' :: Compose [] I Char)
315+ , Example "Compose [] [] Char" "[\"x\"]" (pure 'x' :: Compose [] [] Char)
316+
317+ , Example "Compose3 I I I Char" "\"x\"" (pure 'x' :: Compose3 I I I Char)
318+ , Example "Compose3 I I [] Char" "\"x\"" (pure 'x' :: Compose3 I I [] Char)
319+ , Example "Compose3 I [] I Char" "\"x\"" (pure 'x' :: Compose3 I [] I Char)
320+ , Example "Compose3 I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3 I [] [] Char)
321+ , Example "Compose3 [] I I Char" "\"x\"" (pure 'x' :: Compose3 [] I I Char)
322+ , Example "Compose3 [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3 [] I [] Char)
323+ , Example "Compose3 [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3 [] [] I Char)
324+ , Example "Compose3 [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3 [] [] [] Char)
325+
326+ , Example "Compose3' I I I Char" "\"x\"" (pure 'x' :: Compose3' I I I Char)
327+ , Example "Compose3' I I [] Char" "\"x\"" (pure 'x' :: Compose3' I I [] Char)
328+ , Example "Compose3' I [] I Char" "\"x\"" (pure 'x' :: Compose3' I [] I Char)
329+ , Example "Compose3' I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3' I [] [] Char)
330+ , Example "Compose3' [] I I Char" "\"x\"" (pure 'x' :: Compose3' [] I I Char)
331+ , Example "Compose3' [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3' [] I [] Char)
332+ , Example "Compose3' [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3' [] [] I Char)
333+ , Example "Compose3' [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3' [] [] [] Char)
262334 ]
263335
264336jsonDecoding :: [Assertion]