我有Data.Serialize的问题.当我编码数据结构时,我可以编码作为Serialize类实例的所有数据结构.这非常有效.
然后我通过网络发送它.
但是,解码时遇到问题.解码函数给我一个称为" Either String" 的类型,我不太确定如何进一步使用它来重建我的原始数据结构,因为收件人只知道它以前是一个实例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)
Run Code Online (Sandbox Code Playgroud)
使用eg receiveMessage :: (Serialize a) => Socket -> IO (a, SockAddr)也没有帮助.我怎么能处理这个问题并最好地恢复我的原始数据结构?
Either是一种处理错误的类型.这就像Maybe除非你可以(在这种情况下,一些相关联的任意值String),对应于"错误"情况Maybe的Nothing.
也就是说,Either String a意味着结果可以是a String或要反序列化的数据.
您可以Either通过模式匹配来获取数据.Either有两个构造函数:Left和Right.在这种情况下,Left将有一些字符串,Right将有你的价值.所以你会做这样的事情:
case S.decode msg of
Left str -> ... -- handle your data not being deserialized correctly here
Right res -> ... -- res is your data
Run Code Online (Sandbox Code Playgroud)
此外,您必须指定结果是某些可序列化类型.现在,你的receiveMessage函数承诺返回任何类型a; 相反,您只能从Serialize类中返回一个类型.所以将类型签名更改为类似Serialize a => Socket -> IO (a, SockAddr).
当您实际使用您的函数时,Haskell将知道a应该是什么类型,并将选择适当的反序列化代码.但是,由于此代码仅存在于Serialize类型类的实例中,因此必须在类型签名中指定该代码.
在一个不相关的说明:你不需要$操作员S.decode $ msg.您可以将运算符视为围绕其后面的内容添加parens,因此该S.decode $ msg行相当于S.decode (msg),这是不必要的,可以保留为S.decode msg.