I have a problem with Data.Serialize. When I encode a data structure then I can encode all data structures that are instances of the Serialize class. That works very well.
I then send it over the network.
However, I have a problem when decoding. The decoding function gives me back a type called “Either String” where I am not quite sure how to use this further to reconstruct my original data structure from that the recipient only knows that it had previously been an instance of Serialize.
receiveMessage :: Socket -> IO (a, SockAddr)
receiveMessage s = do
(msg, remoteSockAddr) <- recvFrom s 512
return (S.decode $ msg, remoteSockAddr)
Couldn't match type `a' with `Either String a0'
`a' is a rigid type variable bound by
the type signature for receiveMessage :: Socket -> IO (a, SockAddr)
In the expression: decode $ msg
In the first argument of `return', namely
`(decode $ msg, remoteSockAddr)'
In the expression: return (decode $ msg, remoteSockAddr)
Using e.g. receiveMessage :: (Serialize a) => Socket -> IO (a, SockAddr) is no help either. How could I deal with this and best get back my original data structure?
Eitheris a type for handling errors. It is likeMaybeexcept you can associate an arbitrary value (in this case someString) with the “error” case corresponding toMaybe‘sNothing.That is,
Either String ameans that the result could either be aStringor the data you want to deserialize.You can get your data out of the
Eitherby pattern matching.Eitherhas two constructors:LeftandRight. In this case,Leftwill have some string andRightwill have your value. So you would do something like this:Also, you will have to specify that the result is some serializable type. Right now, your
receiveMessagefunction promises to return any typea; instead, you can only return a type from theSerializeclass. So change the type signature to something likeSerialize a => Socket -> IO (a, SockAddr).When you actually use your function,
Haskellwill know what typeais supposed to be and will choose the appropriate deserialization code. However, since this code only exists for instances of theSerializetypeclass, you have to specify that in the type signature.On an unrelated note: you do not need the
$operator inS.decode $ msg. You can think of the operator as adding parens surrounding what follows it, so theS.decode $ msgline is equivalent toS.decode (msg), which is unnecessary and could be left asS.decode msg.