这是我第一次尝试使用Aeson进行JSON反序列化。我在为我所有的域数据类型检查通用解码函数时遇到了麻烦,尽管为单一的具体类型提供相应的解码函数是可行的。
这里是多态函数。
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
子句不在包含函数的类型签名范围内。 所以,类型变量 dData
签名中 loadDomainData
是完全没有关系的 dData
签名中 decData
. GHC 抱怨说,GHC 中的类型 decData
没有 J.FromJSON
实例,因为类型签名说它没有。 你可以添加它。
decData :: J.FromJSON dData => Maybe dData
或者你可以打开 ScopedTypeVariables
扩展,并修改包含函数的类型签名,以标记为 dData
变量为scoped。
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)