gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 13:39:12 27 4
gpt4 key购买 nike

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

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

直觉是二叉树的类型应该是所有类型中的初始值 T配备恒e: T和二元运算 m: 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必须专门针对BTx为了 x适用于initial_module ;写作(x :: ((BTAlg BT) -> BT) -> BT) initial_module也没有帮助。

关于定义decode_encode的动机的附录:我想说服自己BT事实上与标准实现“同构”

data BTStd = StdEmpty | StdLeaf BTStd BTStd

二叉树;虽然我不知道如何在 Haskell 中做到这一点,但首先要构建 map BT -> BTStdBTStd -> 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) -> zBTrunBT 见证。只要我们将这些证人放在正确的位置,我们就可以继续前进。

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 的一次使用对应于量化类型的一次统一。

关于haskell - Haskell 中通过多态性的递归代数数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24361736/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com