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 Map
We’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 strB
For 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 mapB
Now, 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 res2B
For 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 d
This 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.