haskell - 声明 ToJSON 实例时出现编译错误

标签 haskell types aeson

我在声明我的类型的 ToJSON 实例(同义词)时遇到问题:

{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}

module Argon.Types (ComplexityBlock, AnalysisResult, ResultsOptions(..)
                   , OutputMode(..))
    where

import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL


-- | Hold the data associated to a function binding:
--   (line number, column, function name, complexity)
type ComplexityBlock = (Int, Int, String, Int)

instance ToJSON ComplexityBlock where
    toJSON (l, c, func, cc) = object [ "lineno"     .= l
                                     , "col"        .= c
                                     , "name"       .= func
                                     , "complexity" .= cc
                                     ]

-- | Represent the result of the analysis of one file.
--   It can either be an error message or a list of
--   'ComplexityBlock's.
type AnalysisResult = Either String [ComplexityBlock]

instance ToJSON (FilePath, AnalysisResult) where
    toJSON (p, Left err) = object [ "path"    .= p
                                  , "type"    .= "error"
                                  , "message" .= err
                                  ]
    toJSON (p, Right rs) = object [ "path"   .= p
                                  , "type"   .= "result"
                                  , "blocks" .= rs
                                  ]

导入 bytestring 包并启用 OverloadedStrings 扩展后,我认为它可以工作,但事实并非如此:

/home/miki/exp/argon/src/Argon/Types.hs:31:47:
    No instance for (ToJSON a0) arising from a use of ‘.=’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance ToJSON (FilePath, AnalysisResult)
        -- Defined at src/Argon/Types.hs:29:10
      instance ToJSON ComplexityBlock
        -- Defined at src/Argon/Types.hs:17:10
    In the expression: type .= error
    In the first argument of ‘object’, namely
      ‘[path .= p, type .= error, message .= err]’
    In the expression:
      object [path .= p, type .= error, message .= err]

/home/miki/exp/argon/src/Argon/Types.hs:31:50:
    No instance for (Data.String.IsString a0)
      arising from the literal ‘error’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Data.String.IsString Value
        -- Defined in ‘aeson-0.8.0.2:Data.Aeson.Types.Internal’
      instance (a ~ Data.ByteString.Internal.ByteString) =>
               Data.String.IsString
                 (attoparsec-0.12.1.6:Data.Attoparsec.ByteString.Internal.Parser a)
        -- Defined in ‘attoparsec-0.12.1.6:Data.Attoparsec.ByteString.Char8’
      instance Data.String.IsString
                 Data.ByteString.Builder.Internal.Builder
        -- Defined in ‘Data.ByteString.Builder’
      ...plus four others
    In the second argument of ‘(.=)’, namely ‘error’
    In the expression: type .= error
    In the first argument of ‘object’, namely
      ‘[path .= p, type .= error, message .= err]’

/home/miki/exp/argon/src/Argon/Types.hs:35:46:
    No instance for (ToJSON a1) arising from a use of ‘.=’
    The type variable ‘a1’ is ambiguous
    Note: there are several potential instances:
      instance ToJSON (FilePath, AnalysisResult)
        -- Defined at src/Argon/Types.hs:29:10
      instance ToJSON ComplexityBlock
        -- Defined at src/Argon/Types.hs:17:10
    In the expression: type .= result
    In the first argument of ‘object’, namely
      ‘[path .= p, type .= result, blocks .= rs]’
    In the expression:
      object [path .= p, type .= result, blocks .= rs]

/home/miki/exp/argon/src/Argon/Types.hs:35:49:
    No instance for (Data.String.IsString a1)
      arising from the literal ‘result’
    The type variable ‘a1’ is ambiguous
    Note: there are several potential instances:
      instance Data.String.IsString Value
        -- Defined in ‘aeson-0.8.0.2:Data.Aeson.Types.Internal’
      instance (a ~ Data.ByteString.Internal.ByteString) =>
               Data.String.IsString
                 (attoparsec-0.12.1.6:Data.Attoparsec.ByteString.Internal.Parser a)
        -- Defined in ‘attoparsec-0.12.1.6:Data.Attoparsec.ByteString.Char8’
      instance Data.String.IsString
                 Data.ByteString.Builder.Internal.Builder
        -- Defined in ‘Data.ByteString.Builder’
      ...plus four others
    In the second argument of ‘(.=)’, namely ‘result’
    In the expression: type .= result
    In the first argument of ‘object’, namely
      ‘[path .= p, type .= result, blocks .= rs]’

我不明白为什么类型变量是不明确的。

最佳答案

比较签名:

fromString :: IsString a => String -> a
toJSON :: ToJSON a => a -> Value

从技术上讲,要序列化字符串文字,您的自定义实例使用它们的叠加:

toJSON . fromString :: (IsString a, ToJSON a) => String -> Value

请注意类型变量如何从签名中消失,因此出现了歧义。例如,"error" 可以是 StringValueText,所有这些都具有 IsStringToJSON 实例。

一个快速的解决方法是通过提供显式类型签名来手动解决歧义:

    toJSON (p, Left err) = object [ "path"    .= p
                                  , "type"    .= ("error" :: String)

关于haskell - 声明 ToJSON 实例时出现编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33235365/

相关文章:

Haskell 可能输入 -> 类型

haskell - 对Eta reduce的理解

dynamic - 如何在Scheme中获取值的类型?

haskell - Yesod ExitFailure 1 安装脚手架应用程序时

haskell - 欧拉计划 23 : insight on this stackoverflow-ing program needed

haskell - 根据值范围过滤列表元素

python - 有没有比 int( byte_buffer.encode ('hex' ), 16 ) 更好的方法

json - 如何使用 Haskell Aeson 解析数组

json - 使用 Aeson 解码字符串时遇到问题