Haskell protobuf:不明确的类型变量
Haskell protobuf: ambiguous type variable
通常我知道如何解决模棱两可的类型变量问题,但这次我不知道。长话短说,我使用 protobuf Haskell library for working with protocol buffers。该库让您忘记维护单独的 .proto 文件,如果它分别是编码和解码类型 classes 的实例,它会派生序列化和反序列化数据类型的方法。
我正在 protobuf 之上设计一个简单的协议。有一个主消息数据类型,包含消息 ID、消息类型和一些取决于类型的可选数据。我想要一个函数来获取消息 ID、消息类型和可选数据(必须是 Encode class 的实例)并创建一个新的 MyMessage 实例,其中可选数据提前序列化为 ByteString。
这就是我尝试这样做的方式:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.ByteString (ByteString)
import Data.Int
import Data.Maybe
import Data.Monoid
import Data.ProtocolBuffers
import Data.Serialize
import Data.Text (Text, pack)
import GHC.Generics (Generic)
import GHC.TypeLits
data MyMsgType = MSG_TYPE_1
| MSG_TYPE_2
deriving (Enum, Show)
data MyMessage = MyMessage {
msgId :: Required 1 (Value Int64)
, msgType :: Required 2 (Enumeration MyMsgType)
, cpData :: Optional 3 (Value ByteString)
} deriving (Generic, Show)
instance Encode MyMessage
instance Decode MyMessage
createMessage :: Encode a => Int64 -> MyMsgType -> Maybe a -> MyMessage
createMessage msgId msgType optionalData =
MyMessage (putField msgId) (putField msgType) (putField $ serialiseOptionalData optionalData)
serialiseMessage :: MyMessage -> ByteString
serialiseMessage = runPut . encodeLengthPrefixedMessage
serialiseOptionalData :: Encode a => Maybe a -> Maybe ByteString
serialiseOptionalData Nothing = Nothing
serialiseOptionalData (Just ctx) =
Just . runPut . encodeLengthPrefixedMessage $ ctx
当我尝试使用 createMessage 函数时出现以下错误:
λ> createMessage 1 MSG_TYPE_1 Nothing
<interactive>:7:1:
No instance for (Encode a0) arising from a use of ‘createMessage’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Encode MyMessage -- Defined at test.hs:24:10
instance Encode
(unordered-containers-0.2.6.0:Data.HashMap.Base.HashMap
protobuf-0.2.1.0:Data.ProtocolBuffers.Wire.Tag
[protobuf-0.2.1.0:Data.ProtocolBuffers.Wire.WireField])
-- Defined in ‘protobuf-0.2.1.0:Data.ProtocolBuffers.Encode’
In the expression: createMessage 1 MSG_TYPE_1 Nothing
In an equation for ‘it’: it = createMessage 1 MSG_TYPE_1 Nothing
谁能解释一下为什么会出现这个错误以及如何解决?我不明白编译器到底在哪里看到歧义。
您需要提供有关可选数据类型的更多信息。当您使用 Nothing
作为类型 Maybe a
的值时,编译器无法准确推断出 a
是什么类型。您可以通过显式为 Nothing
指定类型来修复它,如 (Nothing :: Maybe Foo)
.
通常我知道如何解决模棱两可的类型变量问题,但这次我不知道。长话短说,我使用 protobuf Haskell library for working with protocol buffers。该库让您忘记维护单独的 .proto 文件,如果它分别是编码和解码类型 classes 的实例,它会派生序列化和反序列化数据类型的方法。
我正在 protobuf 之上设计一个简单的协议。有一个主消息数据类型,包含消息 ID、消息类型和一些取决于类型的可选数据。我想要一个函数来获取消息 ID、消息类型和可选数据(必须是 Encode class 的实例)并创建一个新的 MyMessage 实例,其中可选数据提前序列化为 ByteString。
这就是我尝试这样做的方式:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.ByteString (ByteString)
import Data.Int
import Data.Maybe
import Data.Monoid
import Data.ProtocolBuffers
import Data.Serialize
import Data.Text (Text, pack)
import GHC.Generics (Generic)
import GHC.TypeLits
data MyMsgType = MSG_TYPE_1
| MSG_TYPE_2
deriving (Enum, Show)
data MyMessage = MyMessage {
msgId :: Required 1 (Value Int64)
, msgType :: Required 2 (Enumeration MyMsgType)
, cpData :: Optional 3 (Value ByteString)
} deriving (Generic, Show)
instance Encode MyMessage
instance Decode MyMessage
createMessage :: Encode a => Int64 -> MyMsgType -> Maybe a -> MyMessage
createMessage msgId msgType optionalData =
MyMessage (putField msgId) (putField msgType) (putField $ serialiseOptionalData optionalData)
serialiseMessage :: MyMessage -> ByteString
serialiseMessage = runPut . encodeLengthPrefixedMessage
serialiseOptionalData :: Encode a => Maybe a -> Maybe ByteString
serialiseOptionalData Nothing = Nothing
serialiseOptionalData (Just ctx) =
Just . runPut . encodeLengthPrefixedMessage $ ctx
当我尝试使用 createMessage 函数时出现以下错误:
λ> createMessage 1 MSG_TYPE_1 Nothing
<interactive>:7:1:
No instance for (Encode a0) arising from a use of ‘createMessage’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Encode MyMessage -- Defined at test.hs:24:10
instance Encode
(unordered-containers-0.2.6.0:Data.HashMap.Base.HashMap
protobuf-0.2.1.0:Data.ProtocolBuffers.Wire.Tag
[protobuf-0.2.1.0:Data.ProtocolBuffers.Wire.WireField])
-- Defined in ‘protobuf-0.2.1.0:Data.ProtocolBuffers.Encode’
In the expression: createMessage 1 MSG_TYPE_1 Nothing
In an equation for ‘it’: it = createMessage 1 MSG_TYPE_1 Nothing
谁能解释一下为什么会出现这个错误以及如何解决?我不明白编译器到底在哪里看到歧义。
您需要提供有关可选数据类型的更多信息。当您使用 Nothing
作为类型 Maybe a
的值时,编译器无法准确推断出 a
是什么类型。您可以通过显式为 Nothing
指定类型来修复它,如 (Nothing :: Maybe Foo)
.