使用文本键在序列化到aeson的功能上更改键名称

时间:2019-04-23 19:18:12

标签: json haskell text aeson

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

我使用“ rec *”作为我要删除的前缀,我的字段开始时是“文本”而不​​是字符串。

以最少的数据开始:

file.unsetf(std::ios::dec);
file.unsetf(std::ios::hex);
file.unsetf(std::ios::oct);

和智能构造函数:

data R3 = R3 { recCode :: Code 
             , recValue :: Value} deriving (Show, Generic)

此实现工作正常:

makeR3 rawcode rawval = R3 code value where
                                     code = rawcode
                                     value = rawval

但是,您可以想象,手动键入从“代码”到“ recCode”的每个键名并不是我想要的。

instance ToJSON R3 where
   toJSON (R3 recCode recValue) = object [ "code" .= recCode, "value" .= recValue]

输出正确:

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 }

错误本身非常清晰,以至于Text无法正常工作,但是我应该改变什么以从json输出中的功能名称中删除前缀 并正确地将文本转换为字符串?

我也没有更改输入,这让我有些困惑,在两个实例中都是Text类型,但是第一个实现可以使用它,而第二个则不能。

我正在使用ihaskell jupyter笔记本。

更新

当我使用以下答案中推荐的Data.Char时:

<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}’

在:

import Data.Char(toLower)

我得到:

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

当我尝试裸露的“掉落”而不是IHaskellPrelude掉落时,我得到:

<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}’

2 个答案:

答案 0 :(得分:3)

您似乎正在使用toLower中的Data.Text,它与Text一起使用,而不是String,所以很自然地,它不适合那里。

相反,您可以在map上使用toLower from Data.CharString

fieldLabelModifier = map toLower . drop 3

答案 1 :(得分:1)

您组成了两个函数T.toLowerdrop 3,但是类型不匹配。确实,如果我们查找类型,则会看到toLower :: Text -> Textdrop :: Int -> [a] -> [a]StringChar的列表,但Text不是:Text可以看作是字符的压缩“块”。

但是我们可以组成类型String -> String的函数,即字段fieldLabelModifier :: String -> String的类型:

import Data.Char(toLower)

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

因此,我们使用Data.Char模块的toLower :: Char -> Char函数,并执行map ping,以便映射字符串中的所有字符。

请注意,如果您只是想导出具有不同选项的FromJsonToJSON,则可以使用 template Haskell ,例如:

{-# 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)

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

注意:我们可以使用合格的导入来使我们更清楚地使用什么功能,例如:
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