在 Haskell 中展平元组

use*_*526 3 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)
Run Code Online (Sandbox Code Playgroud)

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

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

如果不能创建,为什么会这样?

Dan*_*ner 11

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

首先是所有不同大小的元组都是不同的类型构造函数。(,)并且(,,)彼此之间根本没有真正的关系,只是因为它们碰巧用相似的字符序列拼写。由于 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
Run Code Online (Sandbox Code Playgroud)

但综合考虑,他们似乎有点问题:flattenB = flatten不能可能是类型正确的,如果这两个flattenAflattenC是!为输入类型flattenAflattenC统一与输入类型flattenB-它们都是对,其第一分量是本身的一对-但flattenAflattenC返回输出具有不同组分的号码。简而言之,核心问题是,我们在写的时候(a, b),还不知道a或者b本身是否是元组,应该“递归”地展平。

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