我一直致力于一个非常小的程序来获取有关Half Life 2服务器的详细信息(使用protocol-srcds库)。工作流程非常简单;它从文件中获取服务器列表,查询每个服务器,并将输出写入另一个文件(由PHP脚本读取以供显示,因为我与vBulletin绑定)。如果它是在SQL或其他东西中完成的话会很好,但看到我还在学习,现在这已经太过分了!
无论如何,我的问题与序列化有关,即序列化为JSON。现在,我写了一个有争议的帮助函数jsonify
,这样:
jsonify (Just (SRCDS.GameServerInfo serverVersion
serverName
serverMap
serverMod
serverModDesc
serverAppId
serverPlayers
serverMaxPlayers
serverBots
serverType
serverOS
serverPassword
serverSecure
serverGameVersioning)) =
toJSObject [ ("serverName", serverName)
, ("serverMap", serverMap)
, ("serverPlayers", show serverPlayers)
, ("serverMaxPlayers", show serverMaxPlayers) ]
(我正在使用Text.JSON
包)。这显然不太理想。但是,在这个阶段,我不明白使用实例为记录定义序列化程序,而我这样做的尝试在类型系统中遇到了挫败感。
有人可以通过“正确”的方式告诉我这样做吗?我如何定义序列化记录的instance
?我应该在instance
(showJSON?)中使用哪些函数。
提前感谢您的帮助。
答案 0 :(得分:6)
您可能需要考虑使用Data.Aeson
代替可能被视为Text.JSON
的继承者。
使用aeson
为序列化/反序列化定义单独的实例(使用Text.JSON
即使只需要一个,也必须定义两个方向,否则编译会惹恼你 - 除非你让警告静音不知何故),它提供了一些运算符使定义实例更紧凑,例如来自@ hammar的答案的例子可以写得稍微吵一点,如下面的aeson
API所示:
instance ToJSON SRCDS.GameServerInfo where
toJSON (SRCDS.GameServerInfo {..}) = object
[ "serverName" .= serverName
, "serverMap" .= serverMap
, "serverPlayers" .= serverPlayers
, "serverMaxPlayers" .= serverMaxPlayers
]
答案 1 :(得分:1)
您可以做的一件简单事情就是使用record wildcards来减少模式代码。
至于你的类型系统问题,很难在没有看到错误消息的情况下提供帮助以及你到目前为止所尝试的内容,但我怀疑有一件事可能令人困惑的是toJSObject
的结果将不得不被包装在JSObject
数据构造函数中,因为showJSON
的返回类型应该是JSValue
。同样,对象的值也应该是JSValue
类型。最简单的方法是使用他们的 JSON
实例并调用showJSON
来转换值。
instance JSON SRCDS.GameServerInfo where
showJSON (SRCDS.GameServerInfo {..}) =
JSObject $ toJSObject [ ("serverName", showJSON serverName)
, ("serverMap", showJSON serverMap)
, ("serverPlayers", showJSON serverPlayers)
, ("serverMaxPlayers", showJSON serverMaxPlayers) ]