将json写入Haskell中的文件(使用Text而不是[Char])

时间:2016-08-23 00:56:14

标签: json haskell

我正在尝试将对象序列化为JSON字符串并将其写入文件。

在python中,我会做类似的事情:

>>> meowmers = {"name" : "meowmers", "age" : 1}
>>> import json
>>> with open("myfile.json","wb") as f
    json.dump(meowmers, f)

$ cat myfile.json
{"age": 1, "name": "meowmers"}

我在Haskell看到这个

$ stack ghci

{-# LANGUAGE OverloadedStrings #-}
:set -XOverloadedStrings

import GHC.Generics
import Data.Aeson as A
import Data.Text.Lazy as T
import Data.Text.Lazy.IO as I

:{
data Cat = Cat {
      name :: Text
    , age  :: Int
    } deriving Show
:}

let meowmers = Cat {name = "meowmers", age = 1}
writeFile "myfile.json" (encode meowmers)

哦不!

*A T I GHC.Generics> I.writeFile "myfile2.json" (encode meowmers)

<interactive>:34:29:
    Couldn't match expected type ‘Text’
                with actual type ‘bytestring-0.10.6.0:Data.ByteString.Lazy.Internal.ByteString’
    In the second argument of ‘I.writeFile’, namely ‘(encode meowmers)’
    In the expression: I.writeFile "myfile2.json" (encode meowmers)

两个问题:

  1. 这似乎是一个字节串。我该如何使用它?
  2. 如果这不是我想做的,是否有使用Text而不是String的Haskell json序列化解决方案呢?

3 个答案:

答案 0 :(得分:7)

您可以使用Data.Aeson.Text.encodeToLazyText直接将JSON编码为惰性Text值。

{-# LANGUAGE DeriveGeneric #-}

import Data.Aeson.Text (encodeToLazyText)

...

I.writeFile "myfile.json" (encodeToLazyText meowmers)

bytestring是二进制数据的类型 - 不一定是文本。要在bytestring中表示文本数据,您需要使用UTF-8等编码对其进行编码。一旦你有一个bytestring(用UTF-8编码或任何格式有意义),你可以使用Data.ByteString函数将它写入文件:

import qualified Data.ByteString.Lazy as BS

BS.writeFile "myfile.json" (encode meowmers)

要完成这项工作,您需要为Cat类型指定一个ToJSON实例,该实例指定如何使用JSON对其进行编码。您可以使用DeriveGeneric扩展程序自动执行此操作:

data Cat = Cat { ... } deriving (Show, Generic)

instance ToJSON Cat

如果您需要更好地控制生成的JSON的样子,也可以手动执行此操作。

答案 1 :(得分:7)

所以,要解决所有问题(因为大部分工作已经完成)。你实际上有两个问题:

  1. 您正在混合字符串类型
  2. 您没有为<?php $to = "me@mydomain.com"; $subject = "Test Subject"; $txt = "Hello world!"; $headers = "From: hello@gmail.com" . "\r\n" . "CC: anotherme@mydomain.com"; mail($to,$subject,$txt,$headers); ?>
  3. 宣布ToJSON的实例

    以下是一个依赖最新版Cataeson的工作示例(对我来说是textaeson-1.0.0.0

    text-1.2.2.1

    正如您可以从导入中看出的那样,我依靠{-# LANGUAGE OverloadedStrings, DeriveGeneric, DeriveAnyClass #-} import GHC.Generics import Data.Text.Lazy (Text) import Data.Text.Lazy.IO as I import Data.Aeson.Text (encodeToLazyText) import Data.Aeson (ToJSON) data Cat = Cat { name :: Text, age :: Int } deriving (Show, Generic, ToJSON) meowmers = Cat { name = "meowmers", age = 1 } main = I.writeFile "myfile.json" (encodeToLazyText meowmers) 通过aeson在字符串类型之间进行转换。这涉及问题1。

    然后,我使用语言扩展程序encodeToLazyText获取DeriveGeneric的{​​{1}}实例,并将其与扩展程序Generic结合使用以获取{的实例{1}} Cat。该实例的魔力再次是part of aeson

    运行此操作后,我会收到一个包含DeriveAnyClass的新文件ToJSON

答案 2 :(得分:3)

将所有评论和答案汇总成一个(在此处归功于其他人,请接受他们的答案之一)。

  1. 导出GenericToJSON(或者如果您愿意,可以手动编写ToJSON个实例)。这需要更多LANGUAGE个pragma。
  2. 使用较新版本的textencodeToLazyText或使用Data.ByteString.Lazy.writeFile写出字节字符串。
  3. {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE DeriveGeneric #-}
    {-# LANGUAGE DeriveAnyClass #-}
    
    import GHC.Generics
    import Data.Aeson (encode,ToJSON(..))
    import Data.Text.Lazy (Text)
    import qualified Data.ByteString.Lazy as BS
    
    data Cat = Cat { name :: Text
                   , age  :: Int
                   } deriving (Show,Generic,ToJSON)
    
    main =
      do let meowmers = Cat {name = "meowmers", age = 1}
         BS.writeFile "myfile.json" (encode meowmers)
    

    导致:

    tommd@HalfAndHalf /tmp% runhaskell so.hs
    tommd@HalfAndHalf /tmp% cat myfile.json
    {"age":1,"name":"meowmers"}