什么是最有效的方法来序列化有限的(非递归的)代数数据类型,这些数据类型仅由构造函数组成?
例如:
p = A
| B q
q = C
| D r
| E
r = F
| G
手动枚举这个非常小的定义的所有有效组合是可能的:
A 0x00
B C 0x01
B D F 0x02
B D G 0x03
B E 0x04
发布于 2013-03-22 09:10:21
没有完全标准的类可以做到这一点,但是自己做一个是很容易的。我要勾勒出这样做的一种方法:
data P = A | B Q deriving Show
data Q = C | D R | E deriving Show
data R = F | G deriving Show
class Finite a where
allValues :: [a]
instance Finite P where
allValues = [A] ++ map B allValues
instance Finite Q where
allValues = [C] ++ map D allValues ++ [E]
instance Finite R where
allValues = [F] ++ [G]
我用这种方式编写了实例,以表明它非常简单和机械,并且可以通过一个程序来完成(例如,使用泛型编程或使用模板Haskell)。您还可以添加一个实例来为您做一些后续工作,前提是该类型是Bounded
和Enum
:
instance (Bounded a, Enum a) => Finite a where
allValues = [minBound..maxBound]
如果现在将deriving (Bounded, Show)
添加到R
中,那么编写的实例就少了一个!
无论如何,现在我们可以评估allValues :: [P]
并返回[A,B C,B (D F),B (D G),B E]
--然后您可以用[0..]
来zip
来获取您的编码等等。
但这肯定是以前做过的!我并不经常使用序列化(如果有的话),但是快速搜索表明,the binary package和the binary-derive package可以为您做一些类似的事情,而不必自己编写实例。我看看他们是否能先做你想做的事。
发布于 2013-03-22 09:21:19
至于内存中的haskell表示,由于结构是惰性的,所以我们不能表示完全打包的东西,这意味着我们需要在每个级别上都有一个间接的表示。也就是说,拆开包装会让你把这些东西压在一起。但是,据我所知,它不会将嵌套构造函数中的位打包到同一个单词中。
有一个指针标记优化,它在指向指针的指针中插入一些有关构造函数的信息:http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/HaskellExecution/PointerTagging。
有关解压缩的更多信息,请参见:fields
https://stackoverflow.com/questions/15572996
复制