Haskell と Elm と JSON の話
ひげ
$ whoami
名古屋の学生
好きなジャンル: 言語処理系
好きな言語:
Haskell でアルバイトしてる
流石関数型の街名古屋(?)、探したらあった
春から東京...
本題
Elm は JSON つらい?
Elmには組込みでJSONに関するパッケージがある
JSON を任意の型に変換する
他言語で良くあるハッシュマップではなく
変換の関数を 自分で書かなくてはいけない
組込み型の変換関数はある
パーサーコンビネーターみたいに書く(?)
たぶんこれがつらいんだと思う
例
type alias Guid = String
type alias Player =
{ name: String
, active: Bool
, id: Guid
}
player : Decoder Player
player =
succeed Player
|: ("name" := string)
|: ("active" := bool)
|: ("id" := string)
めんどいなら Haskell
Haskell の JSON
HaskellもJSONを任意の型に変換する
aeson パッケージ
型クラスを使ってデコーダー/エンコーダーを定義
する
結局手作業か??
Generics があります!
(正確には Haskell でなくて GHC だけど)
Haskell の Generics
Haskell の型の構造を型として扱う(??)
型クラスのインスタンスを勝手に作ってくれる
雑に言えば
インスタンスを定義する側は楽
型クラスを定義する側が大変
例
{-# LANGUAGE DeriveGeneric #-}
type Guid = String
data Player =
{ name : String
, active : Bool
, id : Guid
} deriving (Generics, Show)
instance FromJSON Player
instance ToJSON Player
Elm を捨てて Haskell を使え
ではない!
使うのは
elm-export
Haskellの型 -> Elmの型
をしてくれるパッケージ
ついでに
JSONデコーダーも生成してくれる
例
こういう型から
data Comment = Comment
{ postId :: Int
, text :: Text
, mainCategories :: (String, String)
, published :: Bool
, created :: UTCTime
} deriving (Generic, ElmType)
例
type alias Comment =
{ postId : Int
, text : String
, mainCategories : (String, String)
, published : Bool
, created : Date
}
decodeComment : Decoder Comment
decodeComment =
decode Comment
|> required "postId" int
|> required "text" string
|> required "mainCategories"
(map2 (,) (index 0 string) (index 1 string))
|> required "published" bool
|> required "created" decodeDate
問題がある
Haskellのレコード型はクソ
ホントはこんなコード書いたらHaskell共和国から追
放される
{-# LANGUAGE DeriveGeneric #-}
type Guid = String
data Player =
{ name : String
, active : Bool
, id : Guid
} deriving (Generics, Show)
Haskellのレコード型はクソ
ホントはこんなコード書いたらHaskell共和国から追
放される
{-# LANGUAGE DeriveGeneric #-}
type Guid = String
data Player =
{ name : String
, active : Bool
, id : Guid -- これこれ
} deriving (Generics, Show)
Elm は .id という関数が生成されるので平気(たぶん)
そこで拡張可能レコード
例
extensible というヤバいパッケージを使う
type Player = Record
'[ "name" >: String
, "active" >: Bool
, "id" >: Guide
]
player :: Player
player =
#name @= "hige" <: #active @= True <: #id @= "123" <: emptyRecord
player ^. #name
参照には lens というヤバいパッケージを使う
拡張可能レコードの JSON は??
これです
instance Forall (KeyValue KnownSymbol FromJSON) xs =>
FromJSON (Record xs) where
parseJSON = withObject "Object" $
v -> hgenerateFor
(Proxy :: Proxy (KeyValue KnownSymbol FromJSON)) $
m -> let k = symbolVal (proxyAssocKey m) in
case HM.lookup (fromString k) v of
Just a -> Field . return <$> parseJSON a
Nothing -> fail $ "Missing key: " `mappend` k
(雑に言えば)
拡張可能レコードという一つの型として扱う
まとめ
Elm で JSON はつらい?
つ elm-format with Haskell
Elm のレコード型を Haskell で書けない?
つ 拡張可能レコード
実際に ElmとHaskellでサンプル書いた記事 がある
ので詳しくはコレを見て(?)
Haskell 最高じゃん
おしまい

Haskell と Elm と JSON の話