我正在尝试理解递归代数数据类型的定义、编码和解码,以及通用多态功能。例如,我尝试通过以下方式实现二叉树的递归类型:
data BTAlg x = Empty | Leaf x x
type BT = forall z. ((BTAlg z) -> z) -> z
直觉上来说,所有具有常量
e:T
和二元操作m:T->T->T
的类型T
中,二叉树类型应该是最初的,也就是作为函子BTAlg
的“初始模型”。换言之,BT
的一个元素是一种为任何这样的模型T
分配T
元素的方式。可以通过对
BT
本身进行模块结构定义来实现。initial_module :: (BTAlg BT) -> BT
initial_module = \s -> case s of
Empty -> (\f -> (f Empty))
Leaf x y -> (\f -> (f (Leaf (x f) (y f))))
作为实现BT模式匹配的一步,我现在想将一个元素x:BT应用于类型BT本身,我认为这是对x进行编码和解码的某种方式。
decode_encode :: BT -> BT
decode_encode x = x initial_module
然而,这段代码导致了一种我无法处理的类型错误:
Couldn't match expected type `(BTAlg z -> z) -> z'
with actual type `BT'
Expected type: BTAlg ((BTAlg z -> z) -> z) -> (BTAlg z -> z) -> z
Actual type: BTAlg BT -> (BTAlg z0 -> z0) -> z0
In the first argument of `x', namely `initial_module'
In the expression: x initial_module
这里有什么问题?我不知道为什么类型检查器无法识别通用类型参数
z
必须在 x
中特化为 BT
,才能将 x
应用于 initial_module
;写成 (x :: ((BTAlg BT) -> BT) -> BT) initial_module
也没有帮助。补充说明关于定义
decode_encode
的动机: 我想说服自己,BT
实际上与标准实现“同构”。data BTStd = StdEmpty | StdLeaf BTStd BTStd
关于二叉树的实现;虽然我不知道如何在Haskell中准确地实现,但一个好的起点是构建映射BT -> BTStd
和BTStd -> BT
,这样可以在两个实现之间来回转换。
toStandard: BT -> BTStd
的定义是将BT
的通用属性应用于BTStd
上的规范BTAlg
模块结构:
std_module :: (BTAlg BTStd) -> BTStd
std_module s = case s of
Empty -> StdEmpty
Leaf x y -> StdLeaf x y
toStandard: BT -> BTStd
toStandard x = x std_module
对于解码函数fromStandard: BTStd -> BT
,我想要做以下操作:
fromStandard :: BTStd -> BT
fromStandard s = case s of
StdEmpty -> initial_module Empty
StdLeaf x y -> initial_module (Leaf (fromStandard x) (fromStandard y))
然而,这会带来与上面直接定义
decode_encode
相同的打字问题:Couldn't match expected type `BT'
with actual type `(BTAlg z0 -> z0) -> z0'
In the return type of a call of `fromStandard'
Probable cause: `fromStandard' is applied to too few arguments
In the first argument of `Leaf', namely `(fromStandard x)'
In the first argument of `initial_module', namely
`(Leaf (fromStandard x) (fromStandard y))'
谢谢你!
z
类型(看起来是实际类型: BTAlg BT -> (BTAlg z0 -> z0) -> z0
),但是应该要保留(看起来是期望类型: BTAlg ((BTAlg z -> z) -> z) -> (BTAlg z -> z) -> z
)。我认为你的映射没有很好地定义(你想做什么?) - josejuan