繁体   English   中英

Haskell中通过多态的递归代数数据类型

[英]Recursive algebraic data types via polymorphism in Haskell

我试图理解给定通用多态的功能的递归代数数据类型的定义,解和编码。 作为一个例子,我尝试通过实现递归类型的二叉树

data BTAlg x = Empty | Leaf x x
type BT = forall z. ((BTAlg z) -> z) -> z

直觉是二叉树的类型应该是所有类型T初始值,其中所有类型T配备有常数e: T和二元运算m: T -> T -> T ,即BTAlg函数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也没有帮助。

I want to convince myself that BT is in fact 'isomorphic' to the standard realization 我想说服自己, BT实际上是标准实现的“同构”

data BTStd = StdEmpty | StdLeaf BTStd BTStd

二叉树; 虽然我不知道如何在Haskell中精确地制作这个,但是首先要建立地图BT -> BTStdBTStd -> BT在两个实现之间来回BTStd -> BT

的定义toStandard: BT -> BTStd是的通用性的应用BT到规范化BTAlg上模块结构BTStd

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))'

谢谢!

如果查看decode_encode的推断类型

:t decode_encode
> decode_encode :: ((BTAlg BT -> (BTAlg z -> z) -> z) -> t) -> t

很明显,GHC已经失去了相当多的多态性。 我不完全确定这里的细节 - 这段代码需要编译ImpredicativeTypes ,这通常是我理解开始崩溃的地方。 但是,有一种保持多态性的标准方法:使用newtype

newtype BT = BT { runBT :: forall z. (BTAlg z -> z) -> z }

newtype建立了同构BT ~ forall z . (BTAlg z -> z) -> z BT ~ forall z . (BTAlg z -> z) -> zBTrunBT见证的BT ~ forall z . (BTAlg z -> z) -> z 只要我们把这些证人放在正确的位置,我们就可以前进。

data    BTAlg x = Empty    | Leaf    x     x
data    BTStd   = StdEmpty | StdLeaf BTStd BTStd
newtype BT      = BT { runBT :: forall z. ((BTAlg z) -> z) -> z }

initial_module :: BTAlg BT -> BT
initial_module s = case s of
  Empty -> BT $ \f -> (f Empty)
  Leaf x y -> BT $ \f -> (f (Leaf (runBT x f) (runBT y f)))

std_module :: (BTAlg BTStd) -> BTStd
std_module s = case s of 
  Empty -> StdEmpty
  Leaf x y -> StdLeaf x y

toStandard :: BT -> BTStd
toStandard x = runBT x std_module

fromStandard :: BTStd -> BT
fromStandard s = case s of
  StdEmpty -> initial_module Empty
  StdLeaf x y -> initial_module (Leaf (fromStandard x) (fromStandard y))

特别值得一提的是,我们使用runBT来控制BT类型lambda的应用时间和次数

decode_encode :: BT -> BT
decode_encode x = runBT x initial_module

runBT一个用途对应于量化类型的一个统一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM