2012-10-31 35 views
5

我對Haskell有點初學者,所以我對嚴格類型的東西苦苦掙扎,只是想知道是否有人可以幫助我創建一個我試圖構建的函數。基本上,它需要一個列表的列表,例如: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)) 
+3

請明確說明你希望addLists [[1,2,3],[7,6,8],[0,3,4]]的結果是什麼。你的問題並不明顯。 – dave4420

+1

看來你已經編輯了你的問題來澄清它,但我恐怕我還是不明白。 'addLists [[1,2,3],[7,6,8],[0,3,4]]'的結果應該是什麼樣子?你給出的例子'foldl(zipWith +)[] [[1,2,3],[0,7,6,8],[0,0,0,3,4]]'檢查,我無法弄清楚你打算做什麼。 – mhwombat

+1

你想要結果是'[1,2 + 7,3 + 6 + 0,8 + 4,4]'='[1,9,9,12,4]'? – mhwombat

回答

3

我想這你想要做什麼

import Data.List (transpose) 

addLists :: Num a => [[a]] -> [a] 
addLists xs = map sum . transpose $ zipWith (\n x -> replicate n 0 ++ x) [0..] xs 
+0

謝謝,你能解釋它是如何工作的嗎?我幾乎可以跟隨,但不完全! –

+0

@npfedwards對不起,我的意思是回來並擴大這個答案,但有一些其他的問題出現了。很快就會得到它,我希望! –

+1

有點更好:'addLists = map sum。轉置。 zipWith(++)(inits(重複0))'。有趣的部分是'轉置',這是一個值得熟悉的'Data.List'函數。由於這是一個作品,你可以單獨演奏每個部分來弄清楚它是如何工作的。 – shachaf

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:發現最長的一個,使用take maxlength.(++ repeat 0)
解決方案2讓他們所有的maxlength:另寫zipWith功能不會停止。

我喜歡的解決方案2.讓我們來看看definition of 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 

OK,讓我們不要再停:

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 

現在你可以用zipWithMore (+)取代zipWith (+)。我會留下深刻的印象給你。

+0

謝謝,很好的幫助! –

+0

'(0:)'不會爲'([0] ++)'節省任何納秒,至少不會對'ghc -O2'節省。 '(:)'有時*比*(++)更好,其中任何一個都適用,但是你不應該讓像那樣的納秒級推測來形成你的代碼。 – shachaf

+1

@shachaf當然不是!我開玩笑地說「保存一納秒或兩秒」,這是不必要的。 「(0:)」雖然比較好,但我想介紹一下這個習慣。誰在乎像這樣的問題納秒?我已經說得更清楚了,但這並不意味着嚴重。 – AndrewC