如何处理记录字段中Haskell的保留关键字? [英] How to deal with Haskell's reserved keywords in record fields?

查看:105
本文介绍了如何处理记录字段中Haskell的保留关键字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JSON 包含 Haskell的关键字 type.但是type不能用作记录字段.

JSON in response of Github Gists Rest API contains Haskell's keyword type. But type couldn't be used as a record field.

因此,它不能用于实现 Aeson的通用 FromJSON/ToJSON实例.

Thus it couldn't be used in implementation of Aeson's Generic FromJSON/ToJSON instances.

import Data.Text (Text)

import GHC.Generics (Generic)

type URL = Text

data OwnerType = User deriving (Show)

data Owner = Owner {
      id :: Int,
      gravatar_id :: Text,
      login :: Text,
      avatar_url :: Text,
      events_url :: URL,
      followers_url :: URL,
      following_url :: URL,
      gists_url :: URL,
      html_url :: URL,
      organizations_url :: URL,
      received_events_url :: URL,
      repos_url :: URL,
      starred_url :: URL,
      subscriptions_url :: URL,
      url :: URL,
      -- type :: Text,
      site_admin :: Bool
  } deriving (Generic, Show)

instance ToJSON Owner
instance FromJSON Owner

问题: 是否有解决此类冲突的适当方法?

Question: Is there a proper approach to deal with such kind of conflicts?

推荐答案

我们可以使用TemplateHaskell解决此问题.代替编写ToJSONFromJON,我们可以使用键的特定映射.

We can solve this by using TemplateHaskell. Instead of writing ToJSON and FromJON, we can use a specific mapping of the keys.

首先,我们必须为不是 类型的字段构造一个名称,例如:

First of all, we have to construct a name for the field that is not type, for instance:

data Owner = Owner {
      id :: Int,
      gravatar_id :: Text,
      login :: Text,
      avatar_url :: Text,
      events_url :: URL,
      followers_url :: URL,
      following_url :: URL,
      gists_url :: URL,
      html_url :: URL,
      organizations_url :: URL,
      received_events_url :: URL,
      repos_url :: URL,
      starred_url :: URL,
      subscriptions_url :: URL,
      url :: URL,
      owner_type :: Text,
      site_admin :: Bool
  } deriving (Generic, Show)

现在,我们可以使用 deriveJSON :: Options -> Name -> Q [Dec] 函数,该函数将构造一个fromJSONtoJSON实例.

Now we can use the deriveJSON :: Options -> Name -> Q [Dec] function that will construct a fromJSON and toJSON instance.

此处的关键是 Options 参数:它包含一个 fieldLabelModifier :: String -> String 字段,该字段可以将字段名称重写为JSON中的键.因此,我们可以在此处生成一个将其重写的函数.

The key here is the Options parameter: it contains a fieldLabelModifier :: String -> String field that can rewrite the names of the fields to the keys in JSON. We can thus here generate a function that will rewrite it.

所以我们首先构造一个函数ownerFieldRename :: String -> String:

So we first construct a function ownerFieldRename :: String -> String:

ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name

因此,除了映射到"type"上的"owner_type"之外,此函数还用作标识函数.

So this function acts as an identity function, except for "owner_type", which is mapped on "type".

所以现在我们可以使用自定义选项调用deriveJSON函数:

So now we can call the deriveJSON function with custom options like:

$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)

或全部:

RenameUtils.hs :

RenameUtils.hs:

module RenameUtils where

ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name

MainFile.hs :

MainFile.hs:

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}

import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))
import RenameUtils(ownerFieldRename)

import Data.Text (Text)

type URL = Text

data Owner = Owner {
      id :: Int,
      gravatar_id :: Text,
      login :: Text,
      avatar_url :: Text,
      events_url :: URL,
      followers_url :: URL,
      following_url :: URL,
      gists_url :: URL,
      html_url :: URL,
      organizations_url :: URL,
      received_events_url :: URL,
      repos_url :: URL,
      starred_url :: URL,
      subscriptions_url :: URL,
      url :: URL,
      owner_type :: Text,
      site_admin :: Bool
  } deriving (Show)

$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)

现在,我们获得一个以type作为键的JSON对象:

Now we obtain a JSON object with type as key:

Prelude Main Data.Aeson> encode (Owner 1 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" True)
"{\"id\":1,\"gravatar_id\":\"\",\"login\":\"\",\"avatar_url\":\"\",\"events_url\":\"\",\"followers_url\":\"\",\"following_url\":\"\",\"gists_url\":\"\",\"html_url\":\"\",\"organizations_url\":\"\",\"received_events_url\":\"\",\"repos_url\":\"\",\"starred_url\":\"\",\"subscriptions_url\":\"\",\"url\":\"\",\"type\":\"\",\"site_admin\":true}"

对于简单的fieldLabelModifier函数,我们不需要编写特定的函数(必须在特定的模块中定义),我们还可以在此处使用 lambda表达式:

For a simple fieldLabelModifier function we do not need to write a specific function (that we have to define in a specific module), we can also use an lambda expression here:

MainFile.hs :

MainFile.hs:

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}

import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))
import Data.Text (Text)

type URL = Text

data Owner = Owner {
      id :: Int,
      gravatar_id :: Text,
      login :: Text,
      avatar_url :: Text,
      events_url :: URL,
      followers_url :: URL,
      following_url :: URL,
      gists_url :: URL,
      html_url :: URL,
      organizations_url :: URL,
      received_events_url :: URL,
      repos_url :: URL,
      starred_url :: URL,
      subscriptions_url :: URL,
      url :: URL,
      owner_type :: Text,
      site_admin :: Bool
  } deriving (Show)

$(deriveJSON defaultOptions {fieldLabelModifier = \x -> if x == "owner_type" then "type" else x} ''Owner)

这篇关于如何处理记录字段中Haskell的保留关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆