5

我是 Haskell 的初学者,所以我在严格类型的东西上有点挣扎,只是想知道是否有人可以帮助我完成我正在尝试构建的功能。基本上,它需要一个列表列表,例如:

[[1,2,3], [7,6,8], [0,3,4]]

并将它们一起添加到一个列表中,将后面的列表按其位置数进行翻译。因此,处理示例列表实际上会执行以下操作:

foldl (zipWith +) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

这是我当前的函数(会出现类型错误):

    addLists :: [[Integer]] -> [Integer]
    addLists [[]] = []
    addLists [[x]] = [x]
    addLists [x:xs] = zipWith (+) [x] ([0]++ (addLists xs))
4

2 回答 2

6

请注意,([0]++)它与 相同(0:),这将使它看起来更整洁并为我们节省一两纳秒。(我在拿纳秒开玩笑——没有人能分辨出什么时候比纳秒快,但无论如何这种方式更好。)

让我们首先考虑制作您需要的列表。我们想要

postponeLists [[1,2,3], [7,6,8], [10,20,30,40]] 
             = [[1,2,3], [0,7,6,8], [0,0,10,20,30,40]]
             = [1,2,3] : ones that should have zero in front of them

这对定义来说已经足够了:

postponeLists [] = []
postponeLists (l:ls) = l : map (0:) (postponeLists ls)

现在你说

foldl (zipWith +) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

但你的意思是

foldl (zipWith (+)) [] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]

但不幸的是,这给了你[]因为zipWith一旦任何列表用完元素就会停止。我们需要一些不停地压缩它们的方法。

解决方案1:找到最长的一个,maxlength使用take maxlength.(++ repeat 0)
解决方案2:编写另一个不会停止的zipWith函数。

我更喜欢方案2。我们看一下定义zipWith

zipWith :: (a->b->c) -> [a]->[b]->[c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = [] -- here's the problem - it stops as soon as any list is empty

好的,我们不要停下来:

zipWithMore :: (a -> a -> a) -> [a] -> [a] -> [a]
zipWithMore f (a:as) (b:bs) = f a b : zipWithMore f as bs
zipWithMore f []      bs      = bs -- if there's more in bs, use that
zipWithMore f as      []      = as -- if there's more in as, use that

现在您可以替换zipWith (+)zipWithMore (+). 我会把重点留给你。

于 2012-10-31T12:21:07.943 回答
3

我认为这可以满足您的要求

import Data.List (transpose)

addLists :: Num a => [[a]] -> [a]
addLists xs = map sum . transpose $ zipWith (\n x -> replicate n 0 ++ x) [0..] xs
于 2012-10-31T12:14:21.730 回答