Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 在同一字段中使用两种不同的可能类型派生Aeson类型类_Haskell_Type Parameter_Aeson_To Json_Fromjson - Fatal编程技术网

Haskell 在同一字段中使用两种不同的可能类型派生Aeson类型类

Haskell 在同一字段中使用两种不同的可能类型派生Aeson类型类,haskell,type-parameter,aeson,to-json,fromjson,Haskell,Type Parameter,Aeson,To Json,Fromjson,我有一个API,它以以下形式返回JSON结果: { “数据”:[1,2,3] } 数据字段可以是两个不同记录的编码,如下所示: newtype ResultsTypeA=ResultsTypeA[ResultTypeA] newtype ResultsTypeB=ResultsTypeB[ResultTypeB] 当我从Haskell查询这个API时,我预先知道我是在处理ResultsTypeA还是ResultsTypeB,因为我在查询中明确要求它 我正在努力的部分是AesonToJSON和

我有一个API,它以以下形式返回JSON结果:

{
“数据”:[1,2,3]
}
数据
字段可以是两个不同记录的编码,如下所示:

newtype ResultsTypeA=ResultsTypeA[ResultTypeA]
newtype ResultsTypeB=ResultsTypeB[ResultTypeB]
当我从Haskell查询这个API时,我预先知道我是在处理
ResultsTypeA
还是
ResultsTypeB
,因为我在查询中明确要求它

我正在努力的部分是Aeson
ToJSON
FromJSON
实例。因为两种结果类型
A
B
最终都是
Int
的列表,所以我不能在json中使用模式匹配器,因为在这两种情况下我只能匹配A
[Int]

这就是为什么我想到做以下事情:

newType apia响应=
蜂群反应{
数据::a
}
newtype ResultsTypeA=ResultsTypeA[ResultTypeA]
newtype ResultsTypeB=ResultsTypeB[ResultTypeB]
然而,我无法理解如何为上述内容编写
ToJSON
FromJSON
实例,因为现在
ApiResponse
有一个类型参数,而在Aeson文档中似乎没有任何地方解释如何使用涉及的类型参数派生这些实例

另一种选择是避免使用类型参数,如下所示:

newtype结果=
结果类型A[结果类型A]
|结果类型B[结果类型B]
新型蜂毒反应=
蜂群反应{
数据::结果
}
在这种情况下,
ToJSON
非常简单:

实例响应,其中
toJSON=genericToJSON$defaultOptions
但是来自JSON的
让我们回到了无法决定结果类型
A
B
之间的问题

也有可能我完全做错了,还有第三种选择我看不到

  • 如果ApiResponse上有一个类型参数,那么
    FromJSON
    /
    ToJSON
    实例会是什么样子
  • 有没有完全不同于上述内容的更好的替代方案来解决这个问题
因为结果类型A和B最终都是Int的列表,所以我不能在FromJSON中使用模式匹配器,因为在这两种情况下我只能匹配[Int]

如果您有一个参数化类型,并且您正在手工编写一个
FromJSON
实例,那么您可以设置一个前提条件,即参数本身必须有一个
FromJSON
实例

然后,在编写解析器时,可以将类型参数的解析器用作定义的一部分。像这样:

{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson

data ApiResponse a =
    ApiResponse {
        _data :: a,
        other :: Bool
    } 

instance FromJSON a => FromJSON (ApiResponse a) where
    parseJSON = withObject "" $ \o -> 
          ApiResponse <$> o .: "data" -- we are using the parameter's FromJSON 
                      <*> o .: "other"
如果我们在ghci中加载文件,我们可以向ApiResponse提供类型参数,并且:


如果还派生了
泛型
,则还可以为
ApiResponse
从JSON自动派生

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
import Data.Aeson
import GHC.Generics

data ApiResponse a =
    ApiResponse {
        _data :: a,
        other :: Bool
    } 
    deriving stock Generic
    deriving anyclass FromJSON
派生股票Generic
使GHC生成数据类型结构的表示,可用于派生其他类型类的实现,
FromJSON
。对于那些通过
通用
机制进行的推导,他们需要使用该方法

生成的实例的格式将是
FromJSON a=>FromJSON(ApiResponse a)
,就像手写的一样。我们可以在ghci中再次检查:

ghci> :set -XPartialTypeSignatures
ghci> :set -Wno-partial-type-signatures
ghci> :instances ApiResponse _
instance FromJSON w => FromJSON (ApiResponse w)
instance Generic (ApiResponse w) 
因为结果类型A和B最终都是Int的列表,所以我不能在FromJSON中使用模式匹配器,因为在这两种情况下我只能匹配[Int]

如果您有一个参数化类型,并且您正在手工编写一个
FromJSON
实例,那么您可以设置一个前提条件,即参数本身必须有一个
FromJSON
实例

然后,在编写解析器时,可以将类型参数的解析器用作定义的一部分。像这样:

{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson

data ApiResponse a =
    ApiResponse {
        _data :: a,
        other :: Bool
    } 

instance FromJSON a => FromJSON (ApiResponse a) where
    parseJSON = withObject "" $ \o -> 
          ApiResponse <$> o .: "data" -- we are using the parameter's FromJSON 
                      <*> o .: "other"
如果我们在ghci中加载文件,我们可以向ApiResponse提供类型参数,并且:


如果还派生了
泛型
,则还可以为
ApiResponse
从JSON自动派生

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
import Data.Aeson
import GHC.Generics

data ApiResponse a =
    ApiResponse {
        _data :: a,
        other :: Bool
    } 
    deriving stock Generic
    deriving anyclass FromJSON
派生股票Generic
使GHC生成数据类型结构的表示,可用于派生其他类型类的实现,
FromJSON
。对于那些通过
通用
机制进行的推导,他们需要使用该方法

生成的实例的格式将是
FromJSON a=>FromJSON(ApiResponse a)
,就像手写的一样。我们可以在ghci中再次检查:

ghci> :set -XPartialTypeSignatures
ghci> :set -Wno-partial-type-signatures
ghci> :instances ApiResponse _
instance FromJSON w => FromJSON (ApiResponse w)
instance Generic (ApiResponse w) 

我不认为有任何Haskell类型用于此专用目的是有意义的。有时候,最好在接口处使用s,然后将相关数据提取到Haskell类型中,而不必以任何方式近似JSON结构。我认为对于参数化类型,您应该能够从JSON派生
ToJSON
。生成的实例的格式为
FromJSON a=>FromJSON(ApiResponse a)
。您还应该为
ResultsTypeA
ResultTypeA
等派生实例。
ResultTypeA
的那些应该基于
Int
的底层实例。这可以通过
GeneralizedNewtypeDeriving
DerivingStrategies
派生新类型(FromJSON,ToJSON)
框架挑战:只使用
[Int]
有什么不对?特别是考虑到“当我从Haskell查询此API时,我提前知道我是在处理
ResultsTypeA
还是
ResultsTypeB
,因为我在查询中明确要求它。”。如果您绝对必须有两种不同的类型,查询者只需应用appr