想知道我是否可以帮助编写这个功能.我正在尝试创建一个反转列表中每个"对"的函数.
module Invert where
invert :: [(a,b)] -> [(b,a)]
invert [(a,b)] = [(b,a)]
Run Code Online (Sandbox Code Playgroud)
当我进入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)]
Run Code Online (Sandbox Code Playgroud)
Pet*_*lák 15
由于列表是递归数据结构,因此您必须递归处理列表以交换其所有元素,或使用一些更高阶函数为您执行处理.如果你定义
invert [(a,b)] = [(b,a)]
Run Code Online (Sandbox Code Playgroud)
它只会转换单元素列表,所有其他输入都会失败并出现错误!
试着考虑一下输入invert:它是一个空列表,还是一个非空列表.在非空列表的情况下,您可以交换第一个元素并递归转换其余元素.
(如果您不想反转invert自己,请使用
invert = map swap
Run Code Online (Sandbox Code Playgroud)
swap来自哪里Data.Tuple.)
所以你想在类型为 的列表上映射一个函数(a, b) -> (b, a)。该函数的(,)类型为b -> a -> (b,a)。所以如果我们翻转它,我们得到a -> b -> (b, a)。现在,如果我们取消它,我们会得到(a, b) -> (b, a):
invert = map (uncurry $ flip (,))
Run Code Online (Sandbox Code Playgroud)
例如
> map (uncurry $ flip (,)) [(1, "a"), (2, "b")]
[("a",1),("b",2)]
Run Code Online (Sandbox Code Playgroud)
顺便说一句,您的模式匹配与您想要的不匹配。定义
invert [(a,b)] = [(b,a)]
Run Code Online (Sandbox Code Playgroud)
说“匹配一个包含单个元组的列表”。如果您有一个包含多个元组的列表,则匹配将失败。此外,正如 Josh Lee 指出的,您需要在列表中的元组之间使用逗号。
解决这个问题的最佳方法:将其分解为更小的问题,然后找到解决这些问题的库函数,或者编写自己的库函数。我总是告诉初学者,这是一个比尝试只编写一个函数更好的练习invert,因为你应该学习以下三件事:
在这种情况下,我们可以将问题分解为:
第二个是map列表上的常用函数,是标准库自带的。你可以尝试编写你自己的版本;对于初学者来说,这种事情总是一个很好的练习:
map :: (a -> b) -> [a] -> [b]
map f [] = ...
map f (x:xs) = ...
Run Code Online (Sandbox Code Playgroud)
正如 Petr 指出的,第一个是swap来自 的函数Data.Tuple。但我们可以轻松地编写自己的:
swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)
Run Code Online (Sandbox Code Playgroud)
现在,当然:
invert :: [(a, b)] -> [(b, a)]
invert = map swap
Run Code Online (Sandbox Code Playgroud)