成对的列表成对的列表Haskell

时间:2019-02-13 18:22:46

标签: haskell polymorphism tuples list-comprehension

基本上我有这个练习: 使用列表推导,编写一个多态函数:

split :: [(a, b)] -> ([a], [b])

将(任何类型的)对列表转换为一对列表。例如,

split [(1, 'a'), (2, 'b'), (3, 'c')] = ([1, 2, 3], "abc")

这是我编写函数的方式,但是它不起作用:

split :: [(a, b)] -> ([a], [b])
split listOfPairs = (([a | a <- listOfPairs]), ([b | b <- listOfPairs]))

有人可以解释为什么我的解决方案不起作用吗?谢谢!

1 个答案:

答案 0 :(得分:6)

类似列表的理解

[a | a <- listOfPairs]
实际上,

仅仅是列表的 identity操作。它将产生与您提供的列表相同的列表,因为您基本上遍历了listOfPairs,并且对于每次迭代,您都会生成元素a

Haskell不执行隐式转换,因此它 not 不从aa <- listOfPairs的类型派生而来,只能是第一个元素。即使有可能,反正也不是一个好主意,因为这会使语言更加“不稳定”,因为类型的微小变化可能会对语义产生重大影响。

为了获得元组的第一个元素,您需要使用模式匹配,例如:

[a | (a, _) <- listOfPairs]

在此,我们将模式的元组的第一个元素与a进行匹配,对于第二个元素,我们将使用:

[b | (_, b) <- listOfPairs]

因此,我们可以这样实现:

split:: [(a,b)] -> ([a],[b])
split listOfPairs = ([a | (a, _) <- listOfPairs], [b | (_, b) <- listOfPairs])

或者我们可以使用map :: (a -> b) -> [a] -> [b]fst :: (a, b) -> asnd :: (a, b) -> b

split:: [(a,b)] -> ([a],[b])
split listOfPairs = (map fst listOfPairs, map snd listOfPairs)

但是上面仍然有一个问题:在这里,我们在同一列表上独立地迭代两次。我们可以通过使用递归来忽略它,例如:

split:: [(a,b)] -> ([a],[b])
split [] = []
split ((a, b):xs) = (a:as, b:bs)
    where (as, bs) = split xs

或者我们可以使用foldr函数:

split :: Foldable f => f (a,b) -> ([a],[b])
split = foldr (\(a,b) (as,bs) -> (a:as,b:bs)) ([],[])

已经有一个Haskell函数可以完全满足您的需求:unzip :: [(a, b)] -> ([a], [b])source code

相关问题