给定存在性数据类型,例如:
data Foo = forall a . (Typeable a, Binary a) => Foo a
我想写instance Binary Foo
。我可以编写序列化(序列化TypeRep
然后序列化值),但我无法弄清楚如何编写反序列化。基本问题是,给定TypeRep
,您需要映射回该类型的类型字典 - 我不知道是否可以这样做。
此问题之前已在haskell邮件列表http://www.haskell.org/pipermail/haskell/2006-September/018522.html上提出,但未给出答案。
答案 0 :(得分:7)
您需要某种方式让每个Binary
实例都可以注册自己(就像在您的witness
版本中一样)。您可以通过将每个实例声明与导出的外部符号捆绑在一起来实现此目的,其中符号名称来自TypeRep
。然后,当您要反序列化时,从TypeRep
获取名称并动态查找该符号(使用dlsym()
或类似的东西)。外部导出导出的值可以是例如解串器函数。
这很疯狂,但它确实有效。
答案 1 :(得分:2)
如果你能做到这一点,你也可以实现:
isValidRead :: TypeRep -> String -> Bool
这将是一个由于某人定义新类型而改变其行为的函数!不是很纯粹......我想(并且希望)人们不能在Haskell中实现它。
答案 2 :(得分:1)
我的答案在某些情况下稍微有效(对我的目的来说不够),但可能是最好的。您可以添加witness
函数来见证您拥有的任何类型,然后反序列化可以在见证表中查找。粗略的想法是(未经测试):
witnesses :: IORef [Foo]
witnesses = unsafePerformIO $ newIORef []
witness :: (Typeable a, Binary a) => a -> IO ()
witness x = modifyIORef (Foo x :)
instance Binary Foo where
put (Foo x) = put (typeOf x) >> put x
get = do
ty <- get
wits <- unsafePerformIO $ readIORef witnesses
case [Foo x | Foo x <- wits, typeOf x == ty] of
Foo x:_ -> fmap Foo $ get `asTypeOf` return x
[] -> error $ "Could not find a witness for the type: " ++ show ty
这个想法是,当你经历时,你可以调用witness
关于在反序列化时可能遇到的每种类型的值。反序列化时,搜索此列表。显而易见的问题是,如果在反序列化之前未能调用witness
,则会发生崩溃。
答案 3 :(得分:1)
这可以在GHC 7.10及之后使用静态指针语言扩展来解决:
'query_string' : {
'query': 'product.name: "' + productName + '"'
+ ' AND cost: xxxx'
}
}
可以找到解决方案的完整说明on this blog post,以及完整的摘录here。