Json in Haskell
In Haskell, we can use the aeson library for JSON encoding and decoding. This library provides built-in support for working with JSON data, including custom data types.
First, let’s import the necessary modules:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
import Data.Aeson
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import Data.Text (Text)
import qualified Data.Text as T
import Data.Map (Map)
import qualified Data.Map as MapWe’ll define two data types to demonstrate encoding and decoding of custom types:
data Response1 = Response1
{ page1 :: Int
, fruits1 :: [Text]
} deriving (Show)
data Response2 = Response2
{ page2 :: Int
, fruits2 :: [Text]
} deriving (Show)
instance ToJSON Response1 where
toJSON Response1{..} = object
[ "Page" .= page1
, "Fruits" .= fruits1
]
instance FromJSON Response1 where
parseJSON = withObject "Response1" $ \v -> Response1
<$> v .: "Page"
<*> v .: "Fruits"
instance ToJSON Response2 where
toJSON Response2{..} = object
[ "page" .= page2
, "fruits" .= fruits2
]
instance FromJSON Response2 where
parseJSON = withObject "Response2" $ \v -> Response2
<$> v .: "page"
<*> v .: "fruits"Now, let’s look at encoding basic data types to JSON:
main :: IO ()
main = do
let bolB = encode True
B.putStrLn bolB
let intB = encode (1 :: Int)
B.putStrLn intB
let fltB = encode (2.34 :: Float)
B.putStrLn fltB
let strB = encode ("gopher" :: Text)
B.putStrLn strBFor slices and maps, which encode to JSON arrays and objects:
let slcD = ["apple", "peach", "pear"] :: [Text]
let slcB = encode slcD
B.putStrLn slcB
let mapD = Map.fromList [("apple", 5), ("lettuce", 7)] :: Map Text Int
let mapB = encode mapD
B.putStrLn mapBNow, let’s encode our custom data types:
let res1D = Response1 1 ["apple", "peach", "pear"]
let res1B = encode res1D
B.putStrLn res1B
let res2D = Response2 1 ["apple", "peach", "pear"]
let res2B = encode res2D
B.putStrLn res2BFor decoding JSON data into Haskell values:
let byt = "{\"num\":6.13,\"strs\":[\"a\",\"b\"]}" :: ByteString
case decode byt of
Just dat -> do
putStrLn $ "Decoded: " ++ show (dat :: Map Text Value)
case Map.lookup "num" dat of
Just (Number n) -> print n
_ -> putStrLn "Failed to extract num"
case Map.lookup "strs" dat of
Just (Array arr) -> print $ head arr
_ -> putStrLn "Failed to extract strs"
Nothing -> putStrLn "Failed to decode"
let str = "{\"page\": 1, \"fruits\": [\"apple\", \"peach\"]}" :: ByteString
case decode str of
Just res -> do
print (res :: Response2)
print $ head $ fruits2 res
Nothing -> putStrLn "Failed to decode Response2"In Haskell, we don’t have a direct equivalent to Go’s json.NewEncoder. However, we can achieve similar functionality by using B.hPutStrLn:
let d = Map.fromList [("apple", 5), ("lettuce", 7)] :: Map Text Int
B.hPutStrLn stdout $ encode dThis Haskell code demonstrates JSON encoding and decoding using the aeson library. It covers basic data types, custom types, and working with more complex nested structures. The aeson library provides a powerful and flexible way to work with JSON in Haskell, with support for automatic derivation of JSON instances for many types.