6

想知道我是否可以在编写这个函数时得到一些帮助。我正在尝试创建一个反转列表中每个“对”的函数。

module Invert where
invert :: [(a,b)] -> [(b,a)]
invert [(a,b)] = [(b,a)]

当我进入时invert [(3,1) (4,1) (5,1)]......它应该给我[(1,3) (1,4) (1,5)......但它给了我......


*Invert> [(3,1) (4,1) (5,1)]

<interactive>:2:2:
    The function `(3, 1)' is applied to two arguments,
    but its type `(t0, t1)' has none
    In the expression: (3, 1) (4, 1) (5, 1)
    In the expression: [(3, 1) (4, 1) (5, 1)]
    In an equation for `it': it = [(3, 1) (4, 1) (5, 1)]
4

3 回答 3

17

由于列表是递归数据结构,因此您必须递归处理列表以交换其所有元素,或者使用一些为您进行处理的更高阶函数。如果你定义

invert [(a,b)] = [(b,a)]

它只会转换单元素列表,所有其他输入都将失败并出现错误!

试着想想输入invert得到:它要么是一个空列表,要么是一个非空列表。在非空列表的情况下,您可以交换第一个元素并递归转换其余元素。

(如果您不想反转invert自己,只需使用

invert = map swap

从哪里来swapData.Tuple

于 2013-02-11T17:18:38.073 回答
5

因此,您想在 type 的列表上映射一个函数(a, b) -> (b, a)。该函数(,)具有类型b -> a -> (b,a)。所以如果我们翻转它,我们得到a -> b -> (b, a). 现在,如果我们取消,我们得到(a, b) -> (b, a)

 invert = map (uncurry $ flip (,))

例如

 > map (uncurry $ flip (,)) [(1, "a"), (2, "b")]
 [("a",1),("b",2)]

顺便说一句,您的模式匹配与您想要的不匹配。定义

invert [(a,b)] = [(b,a)]

“匹配一个包含单个元组的列表”。如果您有一个包含多个元组的列表,则匹配将失败。此外,正如 Josh Lee 所指出的,您需要在列表中的元组之间使用逗号。

于 2013-02-11T17:14:33.330 回答
4

解决此问题的最佳方法:将其拆分为较小的问题,然后找到解决这些问题的库函数,或者编写自己的。我总是告诉初学者,这是一个比尝试只写一个函数更好的练习invert,因为你应该学习以下三件事:

  1. 如何将问题拆分为可重复使用的小块。
  2. 该语言提供的标准库函数。
  3. 如何使用递归来编写小的、可重用的函数,如标准库中的函数。

在这种情况下,我们可以将问题拆分为:

  1. 反转单个元组。
  2. 将函数应用于列表的所有元素,并收集结果列表。

第二个只是map列表上的常用函数,它是标准库自带的。您可以尝试编写自己的版本;对于初学者来说,这种事情总是一个很好的练习:

map :: (a -> b) -> [a] -> [b]
map f []     = ...
map f (x:xs) = ...

正如 Petr 所指出的,第一个是swap函数 from Data.Tuple。但是我们可以很容易地编写我们自己的:

swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)

现在,当然:

invert :: [(a, b)] -> [(b, a)]
invert = map swap
于 2013-02-11T19:21:59.733 回答