2016-08-23 52 views
4

我试图将对象序列化为JSON字符串并将其写入文件。将json写入Haskell中的文件(使用文本而不是[Char])

在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. 如果这不是我想要做的,有没有一个Haskell json序列化解决方案使用文本而不是字符串,它还很简单?

回答

5

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

  1. 你混合字符串类型
  2. 您不必申报Cat

这里ToJSON一个实例是,依赖于最新版本的aeson工作示例和text(对我来说是aeson-1.0.0.0text-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来通过encodeToLazyText在字符串类型之间进行转换。与问题编号为1

涉及然后,我用语言扩展DeriveGeneric获得Generic实例Cat,并使用该结合扩展DeriveAnyClass获得的ToJSON一个实例Cat。那个例子的魔力又是part of aeson

运行此操作,我会得到一个新文件myfile.json,其中包含{"age":1,"name":"meowmers"}

6

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

{-# LANGUAGE DeriveGeneriC#-} 

import Data.Aeson.Text (encodeToLazyText) 

... 

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

A bytestring是一种二进制数据类型 - 不一定是文本。为了用字符串表示文本数据,您需要使用像UTF-8这样的编码进行编码。一旦你有一个字节串(编码为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看起来更精细的控制,您也可以手动执行此操作。

+0

有一种简单的方式来获得该版本Data.Aeson.Text的?似乎打破我的包: - 添加依赖关系时失败: aeson:需要(> = 1.0.0.0),无法解决其依赖关系 – Mittenchops

+0

第二个给我: ''' *主要BS GHC。泛型TI> BS.writeFile “myfile2.json”(编码meowmers) :23:30: 不能匹配预期类型 'BS.ByteString' 与实际类型 'Data.ByteString.Lazy.Internal.ByteString' NB:在'Data.ByteString.Internal'中定义'BS.ByteString' 'Data.ByteString.Lazy.Internal.ByteString' 在'Data.ByteString.Lazy.Internal' 中定义在第二个参数'BS.writeFile',即 '(编码meowmers)' 在表达式中:BS.writeFile“myfile2.json”(encode meowmers) ''' – Mittenchops

+0

对于第二种解决方案,尝试将import改为:import合格Data.ByteString.Lazy作为BS' – ErikR

2

把所有的评论和答案汇总成一个(在这里给其他人点名,请接受他们的答案之一)。

  1. 派生GenericToJSON(或手动编写ToJSON例如,如果你想)。这需要几个LANGUAGE编译指示。
  2. 使用较新版本的textencodeToLazyText或使用Data.ByteString.Lazy.writeFile来写出字节串。

 

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

结果造成:

[email protected] /tmp% runhaskell so.hs 
[email protected] /tmp% cat myfile.json 
{"age":1,"name":"meowmers"} 
+0

谢谢,这很有帮助。 – Mittenchops