haskell - 有漏洞的数据类型

标签 haskell types abstract-data-type

因此,如果我有两种基本相同的数据类型,我可以这样编写它们:

data A t = A1 | A2 | A3 | A4 (B t)
data B t = B1 | B2 | B3 | B4 t

type AX = A X
type AY = A Y

现在可以很容易地在 AX 和 AY 上编写函数,或者如果他们不关心的话也可以在“A t”上编写函数。但那么我该如何编写转换呢?

convert :: AX -> AY
convert (A4 (B4 x)) = A4 (B4 (xToY x))
convert ax = ay -- type error

所以现在我需要手动写出所有其他情况,即使它们都不依赖于类型参数。更糟糕的是,虽然我可以在不依赖参数的情况下使用“A {}”来匹配构造函数,但如果我需要这些参数来重建数据,则这是不可能的。

有更好的方法吗?我觉得 GADT 应该能够表达这一点,但很难看出如何从不依赖于它的术语中消除类型变量。我想我必须为 A1 A2 等设置单独的类型,然后我就会失去封闭性和大小写检查......此外我不想手动编写 Show、Eq 和 Typeable!我能想到的唯一其他方法是重新安排整个结构以隔离变化的部分,即

data A t = Independent | B4 t
data Independent = A1 | A2 | ...

但这使得数据的其他所有用途都难以利用一个转换函数。

当然,另一种选择是忘记类型安全并包含“B4(X Y)”,并在其值错误时添加一些不错的运行时错误。

也许有更好的方法来处理“几乎相同”的数据类型?

更新:所以我通过编写伪 fmap 来解决:

convert :: (a -> b) -> A a -> A b

这至少允许我将转换部分和打包-解包样板分开。我想,足够先进的 TH 可能可以为我生成其中之一。不过,我仍然对其他方法感到好奇。我觉得这种方式仍然不精确,因为它允许用任何东西来填充这个洞,而我真正的意思恰恰是两件事之一。

最佳答案

看起来基本上您想要的是 AB 成为 Functor。幸运的是,您可以允许 Haskell 使用 -XDeriveFunctor 派生这些类型的明显的 Functor 实例。然后,使用以下代码:

data A t = A1 | A2 | A3 | A4 (B t) deriving Functor
data B t = B1 | B2 | B3 | B4 t deriving Functor

...

convert :: AX -> AY
convert a = fmap xToY a

下面是一个示例 GHCi session ,添加了一些 XYxToY 的虚拟定义,并且所有内容都派生 显示:

*Main> convert $ A4 B1
A4 B1
*Main> convert $ A4 (B4 X)
A4 (B4 Y)
*Main> convert $ A2
A2

更新

如果您确实只想允许 ABXY 类型的内容“填充”,你可以像这样约束它们:

class XorY t where

instance XorY X
instance XorY Y

data XorY t => A t = A1 | A2 | A3 | A4 (B t)
data XorY t => B t = B1 | B2 | B3 | B4 t

当然,这将排除制作 AB Functor 的可能性,因此上面概述的技巧将不再起作用.

关于haskell - 有漏洞的数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7185366/

相关文章:

function - 有什么办法可以 "visualize"thunk/function?或者如何查看一般参数的函数

Haskell 函数需要很长时间才能处理

c# - 从加载的程序集中查找实现接口(interface)的对象 - 如何比较类型?

c - 将浮点表达式的结果存储到 C 中的 int 变量中的正确方法是什么?

php: is_numeric 对前导空格和尾随空格的处理方式不同

使用其功能创建 ADT - C

list - 在 Haskell 中配对相邻列表项

security - 如何在 Haskell 中安全地编译和运行第三方代码片段?

scala - 在存在更高种类类型的情况下,如何控制模式匹配中绑定(bind)变量的推断类型

java - BSTSet 使用递归实现方法 contains(T value) 和 add(T value)