2016-08-23 25 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