content: -- file: ch06/JSONClass.hs
  type JSONError = String
  
  class JSON a where
      toJValue :: a -> JValue
      fromJValue :: JValue -> Either JSONError a
  
  instance JSON JValue where
      toJValue = id
      fromJValue = Right
  
  -- file: ch06/JSONClass.hs
  instance JSON Bool where
      toJValue = JBool
      fromJValue (JBool b) = Right b
      fromJValue _ = Left "not a JSON boolean"
  
  -- file: ch06/JSONClass.hs
  instance JSON String where
      toJValue               = JString
  
      fromJValue (JString s) = Right s
      fromJValue _           = Left "not a JSON string"
  
  -- file: ch06/JSONClass.hs
  {-# LANGUAGE TypeSynonymInstances #-}
  
  -- file: ch06/JSONClass.hs
  doubleToJValue :: (Double -> a) -> JValue -> Either JSONError a
  doubleToJValue f (JNumber v) = Right (f v)
  doubleToJValue _ _ = Left "not a JSON number"
  
  instance JSON Int where
      toJValue = JNumber . realToFrac
      fromJValue = doubleToJValue round
  
  instance JSON Integer where
      toJValue = JNumber . realToFrac
      fromJValue = doubleToJValue round
  
  instance JSON Double where
      toJValue = JNumber
      fromJValue = doubleToJValue id
  
  -- file: ch06/JSONClass.hs
  newtype JAry a = JAry {
        fromJAry :: [a]
      } deriving (Eq, Ord, Show)
  
  -- file: ch06/JSONClass.hs
  jary :: [a] -> JAry a
  jary = JAry
  
  -- file: ch06/JSONClass.hs
  newtype JObj a = JObj {
        fromJObj :: [(String, a)]
      } deriving (Eq, Ord, Show)
  
  -- file: ch06/JSONClass.hs
  data JValue = JString String
              | JNumber Double
              | JBool Bool
              | JNull
              | JObject (JObj JValue)   -- was [(String, JValue)]
              | JArray (JAry JValue)    -- was [JValue]
                deriving (Eq, Ord, Show)
  
  -- file: ch06/JSONClass.hs
  jaryFromJValue :: (JSON a) => JValue -> Either JSONError (JAry a)
  
  jaryToJValue :: (JSON a) => JAry a -> JValue
  
  instance (JSON a) => JSON (JAry a) where
      toJValue = jaryToJValue
      fromJValue = jaryFromJValue
  
  -- file: ch06/JSONClass.hs
  listToJValues :: (JSON a) => [a] -> [JValue]
  listToJValues = map toJValue
  
  -- file: ch06/JSONClass.hs
  jvaluesToJAry :: [JValue] -> JAry JValue
  jvaluesToJAry = JAry
  
  -- file: ch06/JSONClass.hs
  jaryOfJValuesToJValue :: JAry JValue -> JValue
  jaryOfJValuesToJValue = JArray
  
  -- file: ch06/JSONClass.hs
  jaryToJValue = JArray . JAry . map toJValue . fromJAry
  
  -- file: ch06/JSONClass.hs
  jaryFromJValue (JArray (JAry a)) =
      whenRight JAry (mapEithers fromJValue a)
  jaryFromJValue _ = Left "not a JSON array"
  
  -- file: ch06/JSONClass.hs
  whenRight :: (b -> c) -> Either a b -> Either a c
  whenRight _ (Left err) = Left err
  whenRight f (Right a) = Right (f a)
  
  -- file: ch06/JSONClass.hs
  mapEithers :: (a -> Either b c) -> [a] -> Either b [c]
  mapEithers f (x:xs) = case mapEithers f xs of
                          Left err -> Left err
                          Right ys -> case f x of
                                        Left err -> Left err
                                        Right y -> Right (y:ys)
  mapEithers _ _ = Right []
  
  -- file: ch06/JSONClass.hs
  import Control.Arrow (second)
  
  instance (JSON a) => JSON (JObj a) where
      toJValue = JObject . JObj . map (second toJValue) . fromJObj
  
      fromJValue (JObject (JObj o)) = whenRight JObj (mapEithers unwrap o)
        where unwrap (k,v) = whenRight ((,) k) (fromJValue v)
      fromJValue _ = Left "not a JSON object"
  