Haskell 类型可存储的确切标准是什么?

Haskell 类型可存储的确切标准是什么?,haskell,containers,gadt,data-kinds,Haskell,Containers,Gadt,Data Kinds,很久以前,我为对称组(和循环组)实现了一种数据类型: newtype Cyclic (n :: Nat) = Cyclic {cIndex :: Integer} data Symmetric (n :: Nat) where S1 :: Symmetric 1 (:.) :: Cyclic n -> Symmetric (n-1) -> Symmetric n 这是一个不均匀的容器,但我不确定这是数组还是列表。正如评论所阐明的,这不是一个问题 如果这是一个数组

很久以前,我为对称组(和循环组)实现了一种数据类型:

newtype Cyclic (n :: Nat) = Cyclic {cIndex :: Integer}

data Symmetric (n :: Nat) where
    S1 :: Symmetric 1
    (:.) :: Cyclic n -> Symmetric (n-1) -> Symmetric n 
这是一个不均匀的容器,但我不确定这是数组还是列表。正如评论所阐明的,这不是一个问题


如果这是一个数组,则可以实现
实例可存储(对称n)
。究竟为什么可能这样做?

可存储的旨在唤起C
struct
s的思想。作为一个
结构
,任何
可存储的类型
都有大小限制
可存储(对称n)
是可能的,因为
对称n
实际上是有界大小。(假设
循环n
s是等价的模
n
),它有
n值,这是有限的,因此不需要无界空间。更具体地说,只要
log2(n!)
位就足够了。注意,对于某些特定的
n
,我谈论的是
symmetricn
。对于不同的
Nat
s
n
m
等,
symmetricn
symmetricm
等是不同的类型,因此它们可能具有不同的大小。对于单个
n::Nat
对称n
具有固定大小

真正的问题是选择编码。为了便于实现,您可以使用递归编码,其中
可存储的n
ceil(log2(n)/8)
字节组成,以保存第一个数字,后跟
可存储的(n-1)
。然后,
Symmetric 1
将是0字节,
Symmetric 2
将是1字节(只使用了一位),
Symmetric 3
将是2字节,
Symmetric 256
将是255字节,
Symmetric 257
将是257字节(因为第一个数字有257个选项,因此需要两个字节)。这当然不是很有效,但您可以清楚地看到,每个
对称n
都有一个定义良好的大小。如果你想深入到
log2(n!)
bits(真的,
ceil(log2(n!)/8)
bytes)的范围,你必须做一些~~~funkymath~~(我不熟悉),但你可以做到

你需要单身人士来做这件事;写作是可能的

instance KnownNat n => Storable (Symmetric n)
但不是

instance Storable (Symmetric n)
类型被擦除,因此第二个
实例
不会被告知
n
是什么,因此无法读取任何内容(或实现
sizeof
等)。它可以写,因为
Symmetric
是GADT,因此包含关于
n
是什么的信息


旁注:对称0不应该是非空的吗

data Symmetric (n :: Nat) where
    S0 :: Symmetric 0
    (:.) :: Cyclic n -> Symmetric (n - 1) -> Symmetric n

Symmetric 0
是从空集到自身的双射集,其中只有一个函数(空集)。

它是一个列表,但这与能够编写
可存储的
实例有点正交。@leftaroundabout我想知道原因。(作为答案)@左撇子要具体,我不知道哈斯克尔是怎么知道的“正交”。“dnundoOS”在“Haskell”和“C++”之间的区别并不重要,因为在C(和C++)中存储数据的位置在Haskell中是重要的。在Haskell中,“true”数组(连续存储)非常罕见;它们可以在
数组
向量
库中找到,但除非性能变得重要,否则通常不会使用它们。正常的Haskell类型
[]
是一个链表;大多数其他容器在内部实现为某种形式的树。在本例中,您正在将
对称
实现为一个链表。@DannyuNDos和至于“正交”注释,leftaroundabout只是说它是否是一个列表与编写
可存储
实例的问题无关。
循环n
具有
整数
是否无关,无界大小?A
循环n
表示从
0
n-1
的数字。从逻辑上讲,这是一个有限数量的值,因此有一个有限大小的编码。您决定将其实现为一个
整数
,这一事实与此无关。例如,您可以说
数据循环n,其中CZ::循环1;CS::Cyclic n->Cyclic(sn)
并在其上构建相同的逻辑。取决于您如何处理它,例如,
Cyclic 10::Cyclic 5
要么无效,要么被视为等于
Cyclic 0
。无论哪种方式,您都不关心范围
0
n-1
之外的任何内容。