Usually I know how to fix ambiguous type variable problems but not this time. Long story short, I use protobuf Haskell library for working with protocol buffers. The library makes you forget about maintaining separate .proto files, it derives the way to serialise and deserialise your data type if it's an instance of Encode and Decode type classes respectively.
I'm designing a simple protocol on top of protobuf. There's a main message data type containing a message id, message type and some optional data that depends on the type. I want to have a function that gets message id, message type and the optional data (which is required to be an instance of Encode class) and creates a new instance of MyMessage with optional data serialised to ByteString in advance.
That's how I try to do this:
{-# 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
When I try using createMessage function I get the following error:
λ> 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
Can someone explain me why this error arises and how to fix it? I don't get where exactly the compiler sees the ambiguity.