首页 > 解决方案 > 在 Haskell 中扁平化元组

问题描述

在 Haskell 中,我们可以展平列表列表 展平列表列表

对于元组的简单情况,我可以看到我们将如何展平某些元组,如下例所示:

flatten :: (a, (b, c)) -> (a, b, c)
flatten x = (fst x, fst(snd x), snd(snd x))

flatten2 :: ((a, b), c) -> (a, b, c)
flatten2 x = (fst(fst x), snd(fst x), snd x)

但是,我正在寻找一个接受任何嵌套元组作为输入并将该元组展平的函数。

在 Haskell 中可以创建这样的函数吗?

如果无法创建,为什么会这样?

标签: haskell

解决方案


不,这真的不可能。有两个障碍需要清除。

首先是所有不同大小的元组都是不同类型的构造函数。(,)并且(,,)彼此之间根本没有真正的关系,只是它们碰巧用相似的字符序列拼写。由于在 Haskell 中有无限多这样的构造函数,因此拥有一个对所有构造函数都感兴趣的函数将需要一个具有无限多实例的类型类。哎呀!

第二个是我们天真地对这样的功能有一些非常自然的期望,这些期望是相互冲突的。假设我们设法创建了一个名为flatten. 如果单独来看,以下任何一段代码乍一看都非常自然:

flattenA :: ((Int, Bool), Char) -> (Int, Bool, Char)
flattenA = flatten

flattenB :: ((a, b), c) -> (a, b, c)
flattenB = flatten

flattenC :: ((Int, Bool), (Char, String)) -> (Int, Bool, Char, String)
flattenC = flatten

但综合起来,它们似乎有点问题:如果两者都是,则flattenB = flatten不可能类型正确的!两种输入类型都与输入类型一致——它们都是对,它们的第一个组件本身就是一对——但是并返回具有不同数量的组件的输出。简而言之,核心问题是,当我们编写 时,我们还不知道or本身是否是一个元组,应该“递归地”展平。flattenAflattenCflattenAflattenCflattenBflattenAflattenC(a, b)ab

只要付出足够的努力,就有可能进行足够的类型级编程来组合一些有时适用于有限大小元组的东西。但它是 1. 大量的前期工作,2. 很少有长期的编程效率回报,以及 3. 即使在使用站点也需要相当多的样板。这是一个糟糕的组合;如果有使用站点样板,那么您最好只编写您首先关心的功能,因为无论如何这样做通常都很短。


推荐阅读