Я создаю сайт в Servant, и мне было интересно, нельзя ли создать экземпляр Generi c для генерации полей ввода.
Я хочу иметь
class ToInputField a where
toInputField :: a -> InputField
Таким образом, пример реализации может быть
instance ToInputField Text where
toInputField t = InputField { type = InputText, value = t, name = "some name which I would like to be derived" }
Теперь, если каждая функция доступа определенного типа реализует этот класс, я хотел бы сделать что-то вроде To JSON.
instance ToJSON Person
Но вместо этого сделайте
class ToForm a where
toForm :: a -> [InputField]
instance ToForm Person
Но вместо этого укажите что-то вроде toInputField :: Text -> a -> InputField
, где Text - это имя поля доступа. Итак, toInputField
может быть реализован следующим образом
instance ToInputField Text where
toInputField n t = InputField { type = InputText, value = t, name = n }
У меня такое ощущение, что это возможно с Generics, но у меня нет опыта создания реализации Generi c. Кроме того, я думаю, что должна быть возможность создать реализацию Generi c для
class NamedFunctor a where
nfmap :: (Text -> b -> c) -> [c]
, где Text - это имя поля доступа. Так что я могу создать форму простым
data Person = Person { pname :: Text, pheight :: Int } deriving (Generic, NamedFunctor)
toForm :: NamedFunctor a => a -> [InputField]
toForm = nfmap toInputField
Так, что я могу вызвать ее с помощью
show . toForm $ User "testName" 172
и получить
"[ InputField { type = InputText, value = "testName", name = "pname" }
, InputField { type = InputNumber, value = "172", name = "pheight" }]"
Причина, по которой я спрашиваю об этом более общий вопрос заключается в том, что я не знаю, как бы реализовать что-либо из них, ни простое, ни обобщенное, но я надеюсь, что что-то вроде обобщенного уже реализовано, так как это кажется действительно полезным и может быть использовано для реализации всевозможные вещи, в которых имена полей имеют значение, например, любая сериализация.