Json 使用文本键将序列化中的键名功能性更改为aeson

Json 使用文本键将序列化中的键名功能性更改为aeson,json,haskell,text,aeson,Json,Haskell,Text,Aeson,我有一个json对象,其中有一个手工制作的ToJSON实例。我想用一个不需要显式枚举键名的函数来替换它 我使用“rec*”作为前缀,我想去掉它,我的字段开始时是文本而不是字符串 从最少的数据开始: data R3 = R3 { recCode :: Code , recValue :: Value} deriving (Show, Generic) 和智能构造函数功能: makeR3 rawcode rawval = R3 code value where

我有一个json对象,其中有一个手工制作的ToJSON实例。我想用一个不需要显式枚举键名的函数来替换它

我使用“rec*”作为前缀,我想去掉它,我的字段开始时是文本而不是字符串

从最少的数据开始:

data R3 = R3 { recCode :: Code 
             , recValue :: Value} deriving (Show, Generic)
和智能构造函数功能:

makeR3 rawcode rawval = R3 code value where
                                     code = rawcode
                                     value = rawval
此实现工作正常:

instance ToJSON R3 where
   toJSON (R3 recCode recValue) = object [ "code" .= recCode, "value" .= recValue]
但正如您所想象的,我不想手工将每个键名从“code”输入到“recCode”

tmp_r3 = makeR3 "TD" "100.42"
as_json = encode tmp_r3

main = do
    let out = encodeToLazyText tmp_r3
    I.putStrLn out
    I.writeFile "./so.json" out
    return ()
输出正确:

{"value":100.42,"code":"TD"}
-- not recValue and recCode, correct!
但是,当我尝试此函数时,它无法像以前那样自动将文本转换为字符串

instance ToJSON R3 where
  toJSON = genericToJSON defaultOptions {
             fieldLabelModifier = T.toLower . IHaskellPrelude.drop 3 }
输出:

<interactive>:8:35: error:
    • Couldn't match type ‘Text’ with ‘String’
      Expected type: String -> String
        Actual type: String -> Text
    • In the ‘fieldLabelModifier’ field of a record
      In the first argument of ‘genericToJSON’, namely ‘defaultOptions {fieldLabelModifier = toLower . IHaskellPrelude.drop 3}’
      In the expression: genericToJSON defaultOptions {fieldLabelModifier = toLower . IHaskellPrelude.drop 3}
<interactive>:8:47: error:
    • Couldn't match type ‘String’ with ‘Text’
      Expected type: String -> Text
        Actual type: String -> String
    • In the second argument of ‘(.)’, namely ‘IHaskellPrelude.drop 3’
      In the ‘fieldLabelModifier’ field of a record
      In the first argument of ‘genericToJSON’, namely ‘defaultOptions {fieldLabelModifier = toLower . IHaskellPrelude.drop 3}’
在:

我得到:

<interactive>:8:35: error:
    • Couldn't match type ‘Char’ with ‘String’
      Expected type: String -> String
        Actual type: String -> Char
    • In the ‘fieldLabelModifier’ field of a record
      In the first argument of ‘genericToJSON’, namely ‘defaultOptions {fieldLabelModifier = Data.Char.toLower . IHaskellPrelude.drop 3}’
      In the expression: genericToJSON defaultOptions {fieldLabelModifier = Data.Char.toLower . IHaskellPrelude.drop 3}
<interactive>:8:55: error:
    • Couldn't match type ‘String’ with ‘Char’
      Expected type: String -> Char
        Actual type: String -> String
    • In the second argument of ‘(.)’, namely ‘IHaskellPrelude.drop 3’
      In the ‘fieldLabelModifier’ field of a record
      In the first argument of ‘genericToJSON’, namely ‘defaultOptions {fieldLabelModifier = Data.Char.toLower . IHaskellPrelude.drop 3}’
:8:35:错误:
•无法将类型“Char”与“String”匹配
预期类型:字符串->字符串
实际类型:String->Char
•在记录的“fieldLabelModifier”字段中
在“genericToJSON”的第一个参数中,即“defaultOptions{fieldLabelModifier=Data.Char.toLower.IHaskellPrelude.drop 3}”
在表达式中:genericToJSON defaultOptions{fieldLabelModifier=Data.Char.toLower.IHaskellPrelude.drop 3}
:8:55:错误:
•无法将类型“String”与“Char”匹配
所需类型:字符串->字符
实际类型:字符串->字符串
•在“(.”的第二个参数中,即“ihaskell prelude.drop 3”
在记录的“fieldLabelModifier”字段中
在“genericToJSON”的第一个参数中,即“defaultOptions{fieldLabelModifier=Data.Char.toLower.IHaskellPrelude.drop 3}”
当我尝试裸体“滴”而不是Ihaskelle Prelude滴时,我得到:

instance ToJSON R3 where
  toJSON = genericToJSON defaultOptions {
             fieldLabelModifier = Data.Char.toLower . drop 3 }

<interactive>:8:55: error:
    Ambiguous occurrence ‘drop’
    It could refer to either ‘BS.drop’, imported from ‘Data.ByteString’
                          or ‘IHaskellPrelude.drop’, imported from ‘Prelude’ (and originally defined in ‘GHC.List’)
                          or ‘T.drop’, imported from ‘Data.Text’
实例到JSON R3,其中
toJSON=genericToJSON-defaultOptions{
fieldLabelModifier=Data.Char.toLower.drop 3}
:8:55:错误:
不明确事件“下降”
它可以引用从“Data.ByteString”导入的“BS.drop”
或“IHaskellPrelude.drop”,从“Prelude”导入(最初在“GHC.List”中定义)
或“T.drop”,从“Data.Text”导入

您可以组合两个函数
T.toLower
drop 3
,但类型不匹配。事实上,如果我们查找类型,我们会看到和。
字符串
字符
的列表,但
文本
不是:可以将
文本
视为压缩的字符“块”

但是,我们可以组成一个类型为
String->String
的函数,该字段的类型为:

在这种情况下,模板Haskell部分将实现
FromJSON
ToJSON
实例

注:我们可以使用合格的导入,以便更清楚地了解我们使用的功能,例如:
import qualified Data.List as L
import qualified Data.Char as C

instance ToJSON R3 where
    toJSON = genericToJSON defaultOptions {
            fieldLabelModifier = map C.toLower . L.drop 3
        }

您似乎正在使用
来降低
数据.Text
中的
值,它与
文本
一起使用,而不是与
字符串
一起使用,因此很自然地,它不适合在那里使用

相反,您可以使用and
将其映射到
字符串上:

fieldLabelModifier = map toLower . drop 3

非常感谢。这给了我
:8:35:错误:不明确的出现“toLower”
导入Data.Char的常用别名是什么?我有前奏曲,Data.Text,Data.ByteString作为BS,Data.Text.Lazy.IO作为I。六个其他字符串转换。我仍在学习,但不幸的是,我还没有发现一个问题,它不需要我导入和处理所有可能的字符串库。@Mittenchops:你可以只隐藏你的
文本的
toLower
,例如使用
导入数据。文本隐藏(toLower)
。但这会阻止我使用它,对吗?我正在程序的其他地方使用它。@Mittenchops:您可以定义两个导入语句:
导入数据。文本隐藏(toLower)
导入限定数据。例如,文本为T
。或者只需以限定的方式导入
Data.Char
。@Mittenchops:智能构造函数通常用于(a)阻止导出数据构造函数,从而阻止模块用户解包构造函数(此处仍在进行),以及(b)预处理验证,但在这里,您没有编写任何预处理或验证逻辑。因此,我们可以将
makeR3
函数定义为
makeR3=R3
。但我们不能使用此函数来解包数据。这似乎与我正在导入的数据。文本冲突。那么,是否将其作为限定项导入?
import Data.Char(toLower)

instance ToJSON R3 where
    toJSON = genericToJSON defaultOptions {
            fieldLabelModifier = map toLower . drop 3
        }
{-# LANGUAGE DeriveGeneric, TemplateHaskell #-}

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

data Test = Test { attribute :: String } deriving Show

$(deriveJSON defaultOptions {fieldLabelModifier = map toUpper . drop 3} ''Test)
import qualified Data.List as L
import qualified Data.Char as C

instance ToJSON R3 where
    toJSON = genericToJSON defaultOptions {
            fieldLabelModifier = map C.toLower . L.drop 3
        }
makeR3 = R3
fieldLabelModifier = map toLower . drop 3