Last active
August 29, 2015 14:16
-
-
Save Decoherence/b69920b4995de3970e96 to your computer and use it in GitHub Desktop.
Haskell JSON: Demonstrates how to automatically derive JSON instances for easy encoding/decoding of a nested data record. Also construct lenses for easy viewing/modification of fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveGeneric #-} | |
{-# LANGUAGE TemplateHaskell #-} | |
import Control.Lens | |
import Data.Aeson | |
import qualified Data.ByteString.Lazy.Char8 as C | |
import GHC.Generics | |
-- For production code, use Text instead of String | |
data Person = Person { _personName :: String | |
, _personAge :: Int | |
, _address :: Address | |
} deriving (Generic) | |
data Address = Address { _street :: String | |
, _city :: String | |
, _state :: String | |
, _zip :: Int | |
} deriving (Generic) | |
makeLenses ''Person | |
makeLenses ''Address | |
instance FromJSON Person | |
instance ToJSON Person | |
instance FromJSON Address | |
instance ToJSON Address | |
-- Optional Show instances for pretty printing | |
-- GHC can derive this for you, i.e. Person {..} deriving (Show, Generic) | |
instance Show Person where | |
show (Person name age add) = "Person: " ++ name ++ ", Age: " ++ show age ++ "\nAddress: " ++ show add | |
instance Show Address where | |
show (Address str cty st zipc) = str ++ " ↩ " ++ cty ++ ", " ++ st ++ " ↩ " ++ show zipc | |
chris :: Person | |
chris = Person "Christopher" 30 (Address "27 Main St" "Rome" "GA" 30161) | |
main :: IO () | |
main = do | |
putStrLn "★ Haskell Person record:" | |
print chris | |
putStrLn "\n★ Person encoded as JSON:" | |
C.putStrLn (encode chris) | |
putStrLn "\n★ Decoding JSON:" | |
case (decode (encode chris) :: Maybe Person) of | |
Just p -> print p | |
Nothing -> putStrLn "Failed to decode." | |
putStrLn "\n★ Lenses are so very useful:" | |
putStrLn ">Two ways to focus on the Address field:" | |
print $ chris ^. address -- infix notation | |
print $ view address chris | |
putStrLn "\n★ Let's modify the age using a function, and directly:" | |
print $ chris & personAge %~ succ -- one year wiser | |
print $ chris & personAge .~ 100 -- extremely wise | |
putStrLn "\n★ Let's change the city to Atlanta:" | |
print $ set (address . city) "Atlanta" chris | |
putStrLn "\n★ Now let's change the entire Address:" | |
print $ set address (Address "Secret" "Roswell" "NM" 01010) chris | |
putStrLn "\n★ And of course, aliens love some JSON:" | |
C.putStrLn $ encode $ set address (Address "Secret" "Roswell" "NM" 01010) chris | |
{- | |
λ main | |
★ Haskell Person record: | |
Person: Christopher, Age: 30 | |
Address: 27 Main St ↩ Rome, GA ↩ 30161 | |
★ Person encoded as JSON: | |
{"_personName":"Christopher","_personAge":30,"_address":{"_zip":30161,"_city":"Rome","_state":"GA","_street":"27 Main St"}} | |
★ Decoding JSON: | |
Person: Christopher, Age: 30 | |
Address: 27 Main St ↩ Rome, GA ↩ 30161 | |
★ Lenses are so very useful: | |
>Two ways to focus on the Address field: | |
27 Main St ↩ Rome, GA ↩ 30161 | |
27 Main St ↩ Rome, GA ↩ 30161 | |
★ Let's modify the age using a function, and directly: | |
Person: Christopher, Age: 31 | |
Address: 27 Main St ↩ Rome, GA ↩ 30161 | |
Person: Christopher, Age: 100 | |
Address: 27 Main St ↩ Rome, GA ↩ 30161 | |
★ Let's change the city to Atlanta: | |
Person: Christopher, Age: 30 | |
Address: 27 Main St ↩ Atlanta, GA ↩ 30161 | |
★ Now let's change the entire Address: | |
Person: Christopher, Age: 30 | |
Address: Secret ↩ Roswell, NM ↩ 1010 | |
★ And of course, aliens love some JSON: | |
{"_personName":"Christopher","_personAge":30,"_address":{"_zip":1010,"_city":"Roswell","_state":"NM","_street":"Secret"}} | |
-} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment