Это вариант использования для обобщений.
import GHC.Generics
data MyData = MyData
{ ...
} deriving (Generic) -- extension: DerivingGeneric
Класс типа Generic
имеет связанный тип Rep
и метод to
(и from
)
to :: MyData -> Rep MyData p {- ignore the p -}
Rep MyData
разворачивается в тип, созданный с M1
, (:*:)
и K1
:
Rep MyData =
M1 D _ (
M1 C _ (
( M1 S _ (K1 _ String) )
:*:
( M1 S _ (K1 _ String) )
)
)
-- the things hidden by underscores carry metadata about MyData
-- (type name, constructor name, field names, whether fields are lazy, etc.).
Так что, если вы можете написать функцию, которая работает для многих комбинаций M1
,(:*:)
, K1
, затем вы можете получить функцию на MyData
композицией с to
.
class GFromMap r where
gFromMap :: Map String String -> Maybe (r p) -- always ignore the p
-- extension: FlexibleContexts
fromMap :: (Generic a, GFromMap (Rep a)) => Map String String -> Maybe a
fromMap m = to <$> gFromMap m
Нам нужно четыре экземпляра GFromMap
.Два для новых типов M1 D
и M1 C
, несущих информацию о MyData
, которые нас не волнуют (имя типа, имена конструкторов).
-- extension: FlexibleInstances
instance GFromMap r => GFromMap (M1 D d r) where
gFromMap m = M1 <$> gFromMap m
instance GFromMap r => GFromMap (M1 C c r) where
gFromMap m = M1 <$> gFromMap m
Один для продуктов (:*:)
-- extension: TypeOperators
instance (GFromMap r1, GFromMap r2) => GFromMap (r1 :*: r2) where
gFromMap m = (:*:) <$> gFromMap m <*> gFromMap m
И еще один для полей, здесь нам нужно извлечь имя поля из метаданных s
, связанных с новым типом M1 S
, используя класс типа Selector
.
-- extension: ScopedTypeVariables, TypeFamilies
-- the type equality (a ~ String) is for better error messages when
-- a record has a field not of type String
instance (a ~ String, Selector s) => GFromMap (M1 S s (K1 i a)) where
gFromMap m = M1 <$> K1 <$> Map.lookup fdName m
where fdName = toUpper <$> selName (undefined :: _t s _r _a) -- we can refer to s thanks to ScopedTypeVariables
Полная суть: https://gist.github.com/Lysxia/f27c078faec11487df2828cdfb81752a