2012-10-31 9 views
5

Jestem trochę początkującym dla Haskella, więc walczę trochę z rzeczami ścisłymi, zastanawiając się, czy ktoś może mi pomóc z funkcją, którą próbuję zbudować . Zasadniczo przyjmuje wykaz list, na przykład:Praca nad listą list w Haskell

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

i dodaje je razem w jednej listy tłumacząc później list od liczby stanowisk po to jest. Więc praca na liście Przykładem może to być rzeczywiście robi coś takiego:

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

Oto mój bieżącej funkcji (która dostaje typu błędy):

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

Należy wyraźnie określić, co ma być wynikiem 'addLists [[1,2,3], [7,6,8], [0,3,4]]' to be. Nie jest to oczywiste z twojego pytania. – dave4420

+1

Wygląda na to, że zredagowałeś swoje pytanie, by je wyjaśnić, ale obawiam się, że nadal nie rozumiem. Jak powinien wyglądać "addLists [[1,2,3], [7,6,8], [0,3,4]]"? Podany przykład, 'foldl (zipWith +) [] [[1,2,3], [0,7,6,8], [0,0,0,3,4]]' nie wpisuje- sprawdź i nie wiem, co masz zamiar zrobić. – mhwombat

+1

Czy chcesz, aby wynik był '[1, 2 + 7, 3 + 6 + 0, 8 + 4, 4]' = '[1,9,9,12,4]'? – mhwombat

Odpowiedz

3

myślę, że robi to, co chcesz

import Data.List (transpose) 

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

Dzięki, możesz wyjaśnić, jak to działa? Mogę za nim podążać, ale nie całkiem! –

+0

@npfedwards Przepraszam, chciałem wrócić i rozszerzyć tę odpowiedź, ale coś innego wymyśliło. Do zobaczenia wkrótce, mam nadzieję! –

+1

Trochę ładniej: 'addLists = suma map. transponuj. zipWith (++) (inits (repeat 0)) '. Interesującą częścią jest 'transpose', która jest funkcją' Data.List', którą warto znać. Ponieważ jest to kompozycja, możesz zagrać z każdą częścią indywidualnie, aby dowiedzieć się, jak to działa. – shachaf

6

Pamiętaj, że ([0]++) to to samo, co (0:), które sprawi, że będzie wyglądać bardziej porządnie i zaoszczędzi nam nanosekundę lub dwie. (Żartuję z nanosekundową rzeczą - nikt nie jest w stanie powiedzieć, że coś jest o nanosekundę szybsze, ale w ten sposób jest jeszcze przyjemniejsze.)

Zastanówmy się najpierw nad stworzeniem potrzebnych list. Chcemy

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 

To wystarczy informacja o definicji:

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

Teraz wspomnianego

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

ale znaczy

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

ale niestety, że daje [] ponieważ zipWith przestaje działać, gdy na jednej z list zabraknie elementów. Potrzebujemy sposobu na skompresowanie ich, aby się nie zatrzymał.

Rozwiązanie 1: znaleźć najdłuższy, uczynić z nich wszystko, co maxlength użyciu take maxlength.(++ repeat 0)
Rozwiązanie 2: napisać inną funkcję zipWith to nie przeszkadza.

wolę rozwiązania 2. Spójrzmy na 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, niech nie zatrzyma wtedy:

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 

Teraz można zastąpić zipWith (+) z zipWithMore (+). Opuszczę ci punchline.

+0

Dzięki, świetna pomoc! –

+0

'(0:)' nie pozwoli ci zaoszczędzić żadnych nanosekund ponad '([0] ++)', przynajmniej nie z 'ghc -O2'. '(:)' czasami * jest * ładniejsze niż '(++)' gdzie albo ma zastosowanie, ale nie powinieneś pozwalać na spekulacje w kształcie nanosekund, które kształtują twój kod. – shachaf

+1

@shachaf Oczywiście, że nie! Wskazałem żartobliwie, mówiąc: "uratuj nanosekundę lub dwie", że to niepotrzebne. '(0:)' jest jednak ładniejsza i chciałem wprowadzić ten nawyk. Kogo obchodzi nanosekundy z takim problemem? Uczyniłem jaśniej, że nie było to przeznaczone na poważnie. – AndrewC

Powiązane problemy