当前位置: 首页 > 知识库问答 >
问题:

Haskell Pro buf:模棱两可的类型变量

吴德辉
2023-03-14

通常我知道如何修复不明确的类型变量问题,但这次我不知道了。长话短说,我使用protobuf Haskell库来处理协议缓冲区。该库使您忘记了单独维护。proto文件,如果数据类型分别是Encode和Decode类型类的实例,则派生序列化和反序列化数据类型的方法。

我正在protobuf之上设计一个简单的协议。有一个主消息数据类型,包含消息id、消息类型和一些取决于类型的可选数据。我想有一个函数来获取消息id、消息类型和可选数据(需要是Encode类的实例),并创建一个新的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

有人能解释一下为什么会出现这个错误以及如何修复它吗?我不知道编译器究竟在哪里看到了歧义。

共有1个答案

储峻
2023-03-14

您需要提供有关可选数据类型的更多信息。当您使用Nothing(无)作为类型a的值时,编译器无法推断a的确切类型。您可以通过显式地将类型指定给Nothing来修复它,如在(Nothing::Maybe Foo)中。

 类似资料:
  • 以下代码是递归变量函数重载的教科书示例。在clang和GCC中,它编译干净,返回36(如预期的那样): 然而,这里有一个小小的修改。它在模板定义中使用依赖类型,而不是直接使用模板参数: 它使用GCC 5.2编译并运行,但使用clang 3.8时失败: 我的问题是双重的。 是否真的有效使用参数包 typename 模式将范围解析运算符应用于包的每个成员,如 ? clang 相对于标准是否正确,或者这

  • 但是,当我尝试相同的示例时,通过将Integer更改为Object,代码编译得很好,输出为String 谁能帮助我理解为什么当输出来自其中有字符串的方法时,签名中有对象的方法是必需的。以及类型错误不明确的原因是什么。

  • 我有一节简单的课 这将输出为10,没有任何错误!!!我原以为这会给我一个ClassCastException,其中有些错误,比如Integer不能转换为HashMap。 出于好奇和愤怒,我尝试了返回值,如下所示

  • 无法找出正确的方法来使用匹配器来识别我要处理的exchange方法的重载。我正在打的电话:

  • 问题内容: 如果在调用时没有设置信号挂起,则线程将被挂起,直到一个或多个挂起。set定义的信号在调用sigwait()时应已被阻止;否则,行为是不确定的。sigwait()对set中的信号的信号动作的影响未指定。 这真的很模棱两可,和这里有什么区别? 而其对如何进行选择的结论并不能完全清楚: 总之,当需要运行代码以响应异步信号来通知线程时,应使用sigwait()处理该信号。或者,如果实现提供信号

  • 我应该如何编写以下Mockito匹配器,以便调用不会有歧义? 我试图在代码中模拟的实际函数调用是: