Haskell の JSONライブラリーである、Aeson のちょっとした紹介記事です。備忘録を兼ねてます。
1. プロジェクト構築
stack new my-project
cd my-project
stack setup
stack build
stack exec my-project-exe
2. ソースコード
まず最初の使用するパッケージを宣言しておきます。
dependencies:
- base >= 4.7 && < 5
- text
- aeson
- bytestring
ソースコードは以下のドキュメントのサンプルコードを使います。
aeson: Fast JSON parsing and encoding
{-# LANGUAGE DeriveGeneric #-}
module AesonTest
(
) where
import Data.Text
import Data.ByteString.Lazy
import Data.Aeson
import GHC.Generics
data Person = Person {
name :: Text
, age :: Int
} deriving (Generic, Show)
instance ToJSON Person
instance FromJSON Person
このソースコードのポイントは以下のinstance宣言です。
instance ToJSON Person
instance FromJSON Person
Person はToJSON と FromJSON のinstanceであると宣言していますが、メソッド関数等の実装はありません。これは GHC の Generic拡張の恩恵で、以下のように Person が Generic を deriving しているからメソッド関数の省略が可能となっています。
data Person = Person {
name :: Text
, age :: Int
} deriving (Generic, Show)
3. 実行
それではAesonを使って「JSON文字列 <=> Person型データ」のエンコード、デコードを確認してみましょう。
ghciを起動します。
stack ghci
AesonTest.hsをロードします。
*Main AesonTest Lib> :l AesonTest
encodeを実行します。
*AesonTest> encode (Person {name = "Joe", age = 12})
<interactive>:2:25: error:
? Couldn't match expected type ‘Text’ with actual type ‘[Char]’
? In the ‘name’ field of a record
In the first argument of ‘encode’, namely
‘(Person {name = "Joe", age = 12})’
In the expression: encode (Person {name = "Joe", age = 12})
エラーとなりました。PersonのnameがTextなのに、入力が[Char]なのでunmatchとなったのです。GHCのOverloadedStrings拡張でこの辺の違いを吸収してもらいます。
:set -XOverloadedStrings
再度、encode を実行します。OKですね。
*AesonTest> encode (Person {name = "Joe", age = 12})
"{\"age\":12,\"name\":\"Joe\"}"
次の decode を実行します。これもOKです。
*AesonTest> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
Just (Person {name = "Joe", age = 12})
最後に encode と decode の型を示しておきます。
import qualified Data.ByteString.Lazy as L
encode :: (ToJSON a) => a -> L.ByteString
decode :: (FromJSON a) => L.ByteString -> Maybe a
今回は以上です。