声明ToJSON实例时编译错误

时间:2015-10-20 11:24:03

标签: 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]’

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

1 个答案:

答案 0 :(得分:4)

比较签名:

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)