14. 使うパッケージ
extensible と lens
今回の目玉パッケージ (ただし lens はオマケ)
Haskell のレコードを扱いやすくしてくれる
(他にも機能はあるんだけど、詳しくは割愛)
-- 普通のレコード
data User = User { id :: Int, name :: String }
-- extensible
type User = Record '[ "id" :> Int, "name" :> String ]
定義は大して変わらないけど...
なぜ標準のレコードが扱いにくいかはココを参照
15. 型
type GitHubLanguage =
Record '[
"type" :> Maybe Text, "aliases" :> Maybe [Text],
"ace_mode" :> Maybe Text, "codemirror_mode" :> Maybe Text,
"wrap" :> Maybe Bool, "extensions" :> Maybe [Text],
"interpreters" :> Maybe [Text], "searchable" :> Maybe Bool,
"language_id" :> Int, "color" :> Maybe Text,
"tm_scope" :> Maybe Text, "group" :> Maybe Text
]
type GitHubLanguages = HashMap Text GitHubLanguage
type FastHubLanguage =
Record '[
"color" :> Maybe Text,
"url" :> Text
]
type FastHubLanguages = HashMap Text FastHubLanguage
16. 型クラス
type C = KeyValue KnownSymbol FromJSON'
instance Forall C xs => FromJSON (Record xs) where
parseJSON = withObject "Object" $
v -> hgenerateFor (Proxy :: Proxy C) $
m -> let k = symbolVal (proxyAssocKey m) in
case HM.lookup (fromString k) v of
Just a -> Field . return <$> parseJSON a
Nothing ->
maybe (fail $ "Missing key: " `mappend` k)
(fmap (Field . return)) $ parseJSON' Nothing
FromJSON 型クラスのインスタンスにすると JSON や
YAML をデコードできる
C 型の制約を満たす Record 型
17. 型クラス
実は前の定義が parseJSON' になってる
YAMLのフィールドが無いときに Nothing にしたい
ので
class FromJSON a => FromJSON' a where
parseJSON' :: Maybe Value -> Maybe (Parser a)
instance FromJSON a => FromJSON' a where
parseJSON' = fmap parseJSON
instance {-# OVERLAPS #-} FromJSON a => FromJSON' (Maybe a) where
parseJSON' = Just . maybe (pure Nothing) parseJSON
19. 関数
diff :: GitHubLanguages -> FastHubLanguages
-> HM.HashMap Text (GitHubLanguage, FastHubLanguage)
diff glangs flangs =
HM.filter ((a, b) -> not $ eqColor a b) $
HM.mapMaybeWithKey (k v -> (,) v <$> HM.lookup k flangs) glangs
-- mapMaybeWithKey :: (k -> a -> Maybe b) -> Map k a -> Map k b
eqColor ::
( Associate "color" (Maybe Text) xs
, Associate "color" (Maybe Text) xs')
=> Record xs -> Record xs' -> Bool
eqColor lang1 lang2 = lang1 ^. #color == lang2 ^. #color
eqColor a b に a と b の型が同じという制約はない
が, eqColor 関数は可換である