Haskell,创建 Html 表单的通用方法

Chr*_*ert 5 generics haskell servant

我正在 Servant 中构建一个站点,并且想知道是否无法创建用于生成输入字段的 Generic 实例。

我想要的是有一个

class ToInputField a where
    toInputField :: a -> InputField
Run Code Online (Sandbox Code Playgroud)

这样,一个示例实现可以是

instance ToInputField Text where
    toInputField t = InputField { type = InputText, value = t, name = "some name which I would like to be derived" }
Run Code Online (Sandbox Code Playgroud)

现在,如果一个类型的每个访问器函数都实现了这个类,我想做一些类似 ToJSON 的事情。

instance ToJSON Person
Run Code Online (Sandbox Code Playgroud)

而是做

class ToForm a where
    toForm :: a -> [InputField]

instance ToForm Person
Run Code Online (Sandbox Code Playgroud)

但是有类似的东西toInputField :: Text -> a -> InputField,其中 Text 是访问器字段的名称。所以toInputField可以这样实现

instance ToInputField Text where
    toInputField n t = InputField { type = InputText, value = t, name = n }
Run Code Online (Sandbox Code Playgroud)

我有一种感觉,这可以通过泛型实现,但我在创建泛型实现方面的经验为零。此外,我认为应该可以为

class NamedFunctor a where
    nfmap :: (Text -> b -> c) -> [c]
Run Code Online (Sandbox Code Playgroud)

其中 Text 是访问器字段的名称。这样我就可以通过简单的方式创建一个表单

data Person = Person { pname :: Text, pheight :: Int } deriving (Generic, NamedFunctor)    

toForm :: NamedFunctor a => a -> [InputField]
toForm = nfmap toInputField
Run Code Online (Sandbox Code Playgroud)

这样我就可以用

show . toForm $ User "testName" 172
Run Code Online (Sandbox Code Playgroud)

并得到

"[ InputField { type = InputText, value = "testName", name = "pname" }
 , InputField { type = InputNumber, value = "172", name = "pheight" }]"
Run Code Online (Sandbox Code Playgroud)

我问这个更笼统的问题的原因是,我不知道如何实现其中的任何一个,既不是简单的也不是广义的,但我希望已经实现了类似广义的东西,因为这似乎非常有用,并且可用于实现所有类型的事情,其中​​字段的名称是相关的,就像任何序列化一样。