2014-11-02 51 views
1

假设你有一个简单的类型,并且想用Aeson将它序列化为JSON。以下是基本设置:如何在Haskell中将参数化类型序列化为JSON?

{-# LANGUAGE DeriveGeneriC#-} 

import Data.Aeson (ToJSON) 
import Data.Aeson (encode) 
import GHC.Generics 

data Spotting = Spotting { 
    state :: String, 
    bird :: String 
} deriving (Show, Generic) 

instance ToJSON Spotting 

现在说你想要的,除了birdstate领域,允许用户在加时赛/自定义元数据传递。对于鸟类发现,也许这是气温,鸟类的密度,潮汐的位置......可能是任何事情,我们事先不知道。

从看着像Twitter API in Haskell的例子,它看起来像你想构建这样的:

data Spotting meta = Spotting { 
    state :: String, 
    bird :: String, 
    meta :: meta 
} deriving (Show, Generic) 

instance ToJSON meta => ToJSON (Spotting meta) 

从我的理解,到目前为止,这是一个参数化类型。目标是现在做一个简单的方法来创建一些JSON。所以我们定义一个这样的函数:

spotting bird state meta = encode $ Spotting { 
    state = state, 
    bird = bird, 
    meta = meta 
} 

但是我不知道该从哪里走。当我这样调用该函数:

record = spotting "Snowy Egret" "California" "low tide" 

它抛出一个错误(我是新来的Haskell所以我仍然在学习如何解释这一切东西的基础知识)

No instance for (Data.String.IsString meta0) 
    arising from the literal `"low tide"' 
The type variable `meta0' is ambiguous 
Possible fix: add a type signature that fixes these type variable(s) 
Note: there are several potential instances: 
    instance Data.String.IsString 
      aeson-0.7.0.6:Data.Aeson.Types.Internal.Value 
    -- Defined in `aeson-0.7.0.6:Data.Aeson.Types.Internal' 
    instance a ~ Data.ByteString.Internal.ByteString => 
      Data.String.IsString 
      (attoparsec-0.12.1.2:Data.Attoparsec.ByteString.Internal.Parser a) 
    -- Defined in `Data.Attoparsec.ByteString.Char8' 
    instance Data.String.IsString Data.Text.Internal.Text 
    -- Defined in `Data.Text' 
    ...plus five others 
In the third argument of `spotting', namely `"low tide"' 
In the expression: 
    spotting "Snowy Egret" "California" "low tide" 
In an equation for `record': 
    record = spotting "Snowy Egret" "California" "low tide" 

发生了什么在这里/你如何得到这个工作?

的最终目标是,不要在meta场传递一个字符串,而是一个类型的对象(但它可以是任何对象),像这样的:

record = spotting "Snowy Egret" "California" MyCustomData { 
    tide = "low" 
} 

你是怎么做到这一点哈斯克尔?

+0

'可能的修复:添加一个修复这些类型变量的类型签名' – alternative 2014-11-02 23:20:25

回答

5

的问题是,因为你有OverloadedStrings开启....

当你键入

record = spotting "Snowy Egret" "California" "low tide" 

编译器需要确定meta是什么类型。因为encode能够解析许多类型,所以它不能告诉编译器使用什么。如果没有OverloadedStrings,"low tide"显然是String类型,但有了它,它可能是StringByteString

你有两个选择中修复这个....

须─

删除OverloadedStrings

或-

明确指定类型。

value = "low tide"::String 
record = spotting "Snowy Egret" "California" value