无法将 Aeson 解码为通用类型的类型检查
Trouble type-checking Aeson decoding into generic types
这是我第一次尝试 JSON 使用 Aeson 进行反序列化。我无法对我所有域数据类型的通用解码函数进行类型检查,即使单个具体类型的相应解码函数确实有效。
这里是多态函数:
import qualified RIO.ByteString.Lazy as BL
import qualified Data.Aeson as J
import qualified Path.Posix as P
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
在最初的失败之后,我为解码器的目标类型插入了一个类型注释,但无济于事。如果我尝试编译它,则会出现以下类型检查错误结果:
• Could not deduce (J.FromJSON dData1)
arising from a use of ‘J.decode’
from the context: J.FromJSON dData
bound by the type signature for:
loadDomainData :: forall dData.
J.FromJSON dData =>
FC.AbsFilePath -> IO dData
at src/Persistence/File/ParticipantRepository.hs:44:1-64
Possible fix:
add (J.FromJSON dData1) to the context of
the type signature for:
decData :: forall dData1. Maybe dData1
• In the expression: J.decode $ BL.fromStrict fileContents
[..]
我错过了什么?感谢四位有识之士!
您根本不需要类型注释。没有它编译不好吗?
您缺少的是 let
或 where
子句中类型签名中的变量不在包含函数的类型签名范围内。因此,loadDomainData
签名中的类型变量 dData
与 decData
签名中的 dData
完全无关。 GHC 抱怨 decData
中的类型没有 J.FromJSON
实例,因为类型签名说它没有。您可以添加它:
decData :: J.FromJSON dData => Maybe dData
或者您可以打开 ScopedTypeVariables
扩展并修改包含函数的类型签名以将 dData
变量标记为作用域:
loadDomainData :: forall dData. J.FromJSON dData => FilePath -> IO dData
同时保持与以前相同的 decData
声明(没有 forall
也没有 constraint
):
decData :: Maybe dData
或者,如上所述,您可以完全删除 decData
的类型签名。因此,以下所有三个都应该有效:
{-# LANGUAGE ScopedTypeVariables #-}
-- Add constraint to `decData` signature
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: J.FromJSON dData => Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
-- Use ScopedTypeVariables
loadDomainData :: forall dData. J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
-- No `decData` signature
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
这是我第一次尝试 JSON 使用 Aeson 进行反序列化。我无法对我所有域数据类型的通用解码函数进行类型检查,即使单个具体类型的相应解码函数确实有效。
这里是多态函数:
import qualified RIO.ByteString.Lazy as BL
import qualified Data.Aeson as J
import qualified Path.Posix as P
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
在最初的失败之后,我为解码器的目标类型插入了一个类型注释,但无济于事。如果我尝试编译它,则会出现以下类型检查错误结果:
• Could not deduce (J.FromJSON dData1)
arising from a use of ‘J.decode’
from the context: J.FromJSON dData
bound by the type signature for:
loadDomainData :: forall dData.
J.FromJSON dData =>
FC.AbsFilePath -> IO dData
at src/Persistence/File/ParticipantRepository.hs:44:1-64
Possible fix:
add (J.FromJSON dData1) to the context of
the type signature for:
decData :: forall dData1. Maybe dData1
• In the expression: J.decode $ BL.fromStrict fileContents
[..]
我错过了什么?感谢四位有识之士!
您根本不需要类型注释。没有它编译不好吗?
您缺少的是 let
或 where
子句中类型签名中的变量不在包含函数的类型签名范围内。因此,loadDomainData
签名中的类型变量 dData
与 decData
签名中的 dData
完全无关。 GHC 抱怨 decData
中的类型没有 J.FromJSON
实例,因为类型签名说它没有。您可以添加它:
decData :: J.FromJSON dData => Maybe dData
或者您可以打开 ScopedTypeVariables
扩展并修改包含函数的类型签名以将 dData
变量标记为作用域:
loadDomainData :: forall dData. J.FromJSON dData => FilePath -> IO dData
同时保持与以前相同的 decData
声明(没有 forall
也没有 constraint
):
decData :: Maybe dData
或者,如上所述,您可以完全删除 decData
的类型签名。因此,以下所有三个都应该有效:
{-# LANGUAGE ScopedTypeVariables #-}
-- Add constraint to `decData` signature
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: J.FromJSON dData => Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
-- Use ScopedTypeVariables
loadDomainData :: forall dData. J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData :: Maybe dData
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)
-- No `decData` signature
loadDomainData :: J.FromJSON dData => FC.AbsFilePath -> IO dData
loadDomainData filePath = do
fileContents <- readFileBinary $ P.toFilePath filePath
let
decData = J.decode $ BL.fromStrict fileContents
case decData of
Just d -> return d
Nothing -> throwString ("Could not decode data file " <> P.toFilePath filePath)