2016-04-18 1 views
1

Обычно я знаю, как исправить неоднозначные переменные типа, но не в этот раз. Короче говоря, я использую protobuf Библиотека Haskell для работы с protocol buffers. Библиотека заставляет вас забыть о сохранении отдельных файлов .proto, она выводит способ сериализации и десериализации вашего типа данных, если это экземпляр классов типа Encode и Decode соответственно.Haskell protobuf: неоднозначная переменная типа

Я разрабатываю простой протокол поверх протобуфа. Существует тип данных основного сообщения, содержащий идентификатор сообщения, тип сообщения и некоторые дополнительные данные, которые зависят от типа. Я хочу иметь функцию, которая получает идентификатор сообщения, тип сообщения и необязательные данные (который должен быть экземпляром класса 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 

Может кто-нибудь объяснить мне, почему возникает эта ошибка и как ее исправить Это? Я не понимаю, где именно компилятор видит двусмысленность.

ответ

6

Необходимо указать более подробную информацию о типе ваших дополнительных данных. Когда вы используете Nothing в качестве значения типа Maybe a, компилятор не может определить, какой именно тип a есть. Вы можете исправить это, явно указав тип Nothing, как в (Nothing :: Maybe Foo).

+0

cheers mate, вы не можете себе представить, сколько времени я потратил, пытаясь выяснить, что не так :) –