haskell中的Record或简单ADT几乎等同于 boxed tuple。是否有一种方法(理想情况下是一些花哨的扩展或来自haksell平台的库)允许在此类类型和tuple之间进行转换?
我是Haskell的新手,我正在尝试用Haskell构建一些报表工具。这涉及到读/写csv文件和数据库表。使用元组的时候事情很简单,但是在使用普通类的时候会涉及到一些样板。样板在两种方式上几乎是一样的,但是我没有找到一个好的方法来只做一次,除了可能做一个转换(数据<->元组)并使用从元组到CSV/表的本地转换。
更新
到目前为止,我得到的所有答案都是假设我需要完全通用的东西,我想要元组。我不想要元组,我有元组,我不想要它们,因此需要转换它们。事实上,我只是想减少锅炉板(到0:-)),但我不需要函数对每个类型都有相同的名称。
例如,我可以通过取消元组的一个构造函数来轻松地将元组转换为任何内容。问题是我需要uncurryN,但我在任何地方都找不到它(除了在模板haskell教程中)。反之则更难做到。
我不是在寻求解决方案(尽管我得到的所有答案都很棒,因为我不熟悉Haskell中元编程的不同方式),而是更多,因为我不喜欢重新发明轮子,如果轮子已经存在的话(例如这个uncurryN,可以一直手写到20岁,然后装在漂亮的包里)
已更新2
显然,一个uncurry包存在,但它仍然解决了一半的问题。
5条答案
按热度按时间tyu7yeag1#
你可能想看看GHC.Generics。它基本上把每个ADT编码为乘积(
(,)
)和和和(Either
)。作为一个例子,下面是你如何使用泛型来显示这种表示:你可以在GHC.Generics模块中找到更多的文档。我还发现关于它的论文A Generic Deriving Mechanism for Haskell相当具有可读性(这是我读过的为数不多的论文之一)。
f87krz0w2#
lens库,在Control.Lens.Iso和Control.Lens.Wrapped模块中,有几个实用程序可以简化这种转换。不幸的是,目前模板Haskell机制不处理记录,只处理新类型,所以你必须自己定义示例。例如:
现在,我们可以轻松地打包和解包:
我们也可以使用一个作用于元组的函数来修改
Foo
:反过来说:
omjgkv6w3#
如果您想要真实的的n元组(而不仅仅是语义上等价的其他数据),那么没有Template Haskell将非常麻烦。
例如,如果要将
进入
GHC.Generics
和SYB
都会有问题,因为结果类型需要根据数据类型的字段而不同。即使两者都被称为“元组”,(Int, String, Int)
和(String, String, Int, Int)
也是完全独立的类型,并且没有方便的方法来以通用方式处理n元元组。下面是使用GHC.Generics
实现上述目的的一种方法:上面的工作,但它需要大量的工作(我不能很快弄清楚,如果它可以不使用
UndecidableInstances
)。现在,您 * 真正 * 想要做的可能只是跳过元组,使用泛型直接转换为CSV。我假设您正在使用
csv-conduit
,并希望生成ToRecord
类型类的示例。这里有一个例子
现在,您可以轻松地为自定义类型创建示例。
针对您更新后的问题:您可能会对
tuple
包(尤其是Curry
)感兴趣,它包含uncurryN
和curryN
的实现,用于最多15个元素的元组。9gm1akwq4#
在某些情况下,你可以使用unsafeCoerce。函数的名字应该是一个非常明确的警告,要非常小心。特别是,行为取决于编译器,甚至编译器的版本。
d5vmydt95#
generic-lens
中的函数_Ctor
将任何记录值转换为元组,反之亦然,不使用模板haskell。