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

Mit*_*ops 5 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"}
Run Code Online (Sandbox Code Playgroud)

我在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)
Run Code Online (Sandbox Code Playgroud)

不好了!

*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)
Run Code Online (Sandbox Code Playgroud)

两个问题:

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

Tik*_*vis 8

您可以Text使用Data.Aeson.Text.encodeToLazyText直接将JSON编码为延迟值.

{-# LANGUAGE DeriveGeneric #-}

import Data.Aeson.Text (encodeToLazyText)

...

I.writeFile "myfile.json" (encodeToLazyText meowmers)
Run Code Online (Sandbox Code Playgroud)

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

import qualified Data.ByteString.Lazy as BS

BS.writeFile "myfile.json" (encode meowmers)
Run Code Online (Sandbox Code Playgroud)

要使这项工作,您需要为您的Cat类型提供一个ToJSON实例,指定如何在JSON中对其进行编码.您可以使用DeriveGeneric扩展名自动执行此操作:

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

instance ToJSON Cat
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*lec 8

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

  1. 你正在混合字符串类型
  2. 您没有ToJSON声明的实例Cat

这是一个依赖于最新版本aesontext(对我来说是aeson-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)
Run Code Online (Sandbox Code Playgroud)

正如你可以从导入中看到的那样,我依赖于aeson在字符串类型之间进行转换encodeToLazyText.这涉及问题1.

然后,我使用语言扩展DeriveGeneric来获取Generic实例Cat,并将其与扩展一起使用DeriveAnyClass以获取ToJSONfor 的实例Cat.该实例的魔力再次成为其中的一部分aeson.

运行它,我得到一个myfile.json包含{"age":1,"name":"meowmers"}在其中的新文件.