1

我对 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)

使用 eg receiveMessage :: (Serialize a) => Socket -> IO (a, SockAddr)也无济于事。我该如何处理并最好地取回我的原始数据结构?

4

1 回答 1

8

Either是一种处理错误的类型。就像Maybe您可以将任意值(在本例中为 some String)与对应于Maybe's的“错误”情况相关联Nothing

也就是说,Either String a意味着结果可能是 aString或您要反序列化的数据。

您可以Either通过模式匹配获取数据。Either有两个构造函数:LeftRight. 在这种情况下,Left会有一些字符串并且Right会有你的值。所以你会做这样的事情:

case S.decode msg of
  Left str  -> ... -- handle your data not being deserialized correctly here
  Right res -> ... -- res is your data

此外,您必须指定结果是某种可序列化的类型。现在,您的receiveMessage函数承诺返回任何类型a;相反,您只能从Serialize类中返回一个类型。因此,将类型签名更改为类似Serialize a => Socket -> IO (a, SockAddr).

当你实际使用你的函数时,Haskell会知道a应该是什么类型,并会选择适当的反序列化代码。但是,由于此代码仅存在于类型类的实例中Serialize,因此您必须在类型签名中指定它。

$在不相关的说明中:您不需要S.decode $ msg. 您可以将运算符视为在其后添加括号,因此该S.decode $ msg行等效于S.decode (msg),这是不必要的,可以保留为S.decode msg

于 2012-06-28T22:27:15.293 回答