我有一个带有手工制作的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}’
答案 0 :(得分:3)
您似乎正在使用toLower
中的Data.Text
,它与Text
一起使用,而不是String
,所以很自然地,它不适合那里。
相反,您可以在map
上使用toLower
from Data.Char
和String
:
fieldLabelModifier = map toLower . drop 3
答案 1 :(得分:1)
您组成了两个函数T.toLower
和drop 3
,但是类型不匹配。确实,如果我们查找类型,则会看到toLower :: Text -> Text
和drop :: Int -> [a] -> [a]
。 String
是Char
的列表,但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,以便映射字符串中的所有字符。
请注意,如果您只是想导出具有不同选项的FromJson
和ToJSON
,则可以使用 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部分将实现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 }
注意:对于智能构造函数,您可以将该表达式简化为:
makeR3 = R3