Liczby z listy podzielne przez 3

0

Witam mam trochę trudności z haskellem dlatego proszę o pomoc.
Chciałem zrobić następujące zadanie, napisac dunckce podzielnePrzez3 z sygnatura ktora dla przekazanej listy ma zwrocic liste liczb podzielnych przez 3.

no wiec na poczatku musze podac typ danych, wiec wrowadzam liste i otrzymuje liste
podzielPrzez3 :: [a]->[a]
i na razie moje zalozenie jest takie ze podaje liste i jezeli element listy jest mod 3 = 0 to wypisuje go

podzielPrzez3 [a] = if a mod 3 then a

oczywiscie to nie dziala :) nawet sie nie kompiluje, czy ktos na spokojnie moze mi wskazac blad i pomoc z tym zadaniem.

0

Błędów od cholery i ciut ciut:

  1. Haskell jest silnie typowany, nie ma automatycznej konwersji Int -> Bool
  2. if wymaga else zawsze, każde wyrażenie musi coś produkować
  3. przetwarzasz listę, zapisałeś pattern na listę z pojedynczym elementem
  4. używasz funkcji jako operatora, bez notacji infiksowej

Najpierw przypadek bazowy:

podzielnePrzez3 [] = [] -- dla pustej listy nie robimy nic

następne właściwy krok, aktualnie z if, dekompozycja listy, jeżeli podzielne to osadzamy element i wynik filtracji reszty, w przeciwnym wypadku wyłącznie resztę.

podzielnePrzez3 (x:xs) = if x `mod` 3 == 0 then x : podzielnePrzez3 xs else podzielnePrzez3 xs

całość można zapisać z pattern guardem:

podzielnePrzez3 (x:xs) | x `mod` 3 == 0 = x : podzielnePrzez3 xs
                       | otherwise      = podzielnePrzez3 xs

Tylko po co się rozdrabniać?

podzielnePrzez3 = filter $ \n -> n `mod` 3 == 0
-- ew. w point-free
podzielnePrzez3 = filter ((== 0) . (`mod` 3))
0

Inny wariant to wykorzystanie list-comprehension:

podzielnePrzez3 xs = [ x | x <- xs, x `mod` 3 == 0 ]

lub fakt, że lista jest monadą:

podzielnePrzez3 xs = do x <- xs; guard $ x `mod` 3 == 0; return x
0

Dzięki wielkie za wytłumaczenie!

Niby coś zaczyna świtać, mam mały problem ze zrozumieniem tego zapisu (x:xs).

0

: to konstruktor listy (cons), po lewej stronie element, po prawej ogon. Konstruktory używa się do konstruowania obiektów jak i ich "dekonstrukcji" z użyciem pattern matchingu, x:xs jako argument funkcji oznacza "głowę listy nazwiemy x, ogon xs". Zapis listy w formie [1, 2, 3, 4] jest równoważny 1 : 2 : 3 : 4 : []. Powinieneś przerobić chociaż jakiś tutorial, np. http://learnyouahaskell.com/, względnie kompletny i pisany "idiotoodpornie".

0

Dzięki wielkie, tutorial bardzo fajny. Mam małe problemy z deklaracją typów.

teraz moje zadanie polega na porownaniu dwoch wrpowadzonych list, jezeli sa identyczen to komunikat true jezeli nie to false.
Sprawdzenie list napisalem tyle ze nie wiem jak teraz napisac deklaracje typow tak zeby zwrocic Bool.

 czyRozne []_= []
czyRozne _[]= []
czyRozne (x:xs) (y:ys) = if x==y  then (x,y) : czyRozne xs ys else czyRozne xs ys
0
czyRozne _ [] = true
czyRozne [] _ = true
czyRozne (x:xs) (y:ys) = if x == y then czyRozne xs xy else false
0

Hmm wyglada rozsadnie :P ale bez opisu typu funkcji nie chce ruszyc.
Wydaje mi sie ze bedzie podobny do tego

czyRozne ::[a]->[b]->Bool

No ale ten jest błędny

0

Nie wygląda rozsądnie bo winnerfresh nie rozumie chyba ani konstruktorów typów, ani rekurencji. Zapisane w czytelniejszej formie, z użyciem pattern guardów:

czyRozne _ [] = True
czyRozne [] _ = True
czyRozne (x:xs) (y:ys) | x == y    = czyRozne xs xs
                       | otherwise = False

Warunek jest najzwyczajniej w świecie błędny, powinien być przeciwny (/=), "kontynuuj póki pary elementów trzymają własność". Po prawidłowym użyciu Boola inferencja typów sama sobie poradzi, jak w większości wypadków nie ma potrzeby pisać sygnatur.

czyRozne ::[a]->[b]->Bool

Jest błędne, nie porównujesz elementów różnych typów, dodatkowo muszą one być porównywalne, być instancjami Eq. Całość w prawidłowej formie przedstawia się następująco:

czyRozne :: Eq a => [a] -> [a] -> Bool -- zbędna, z kodu zostanie wywynioskowana identyczna
czyRozne _ [] = True
czyRozne [] _ = True
czyRozne (x:xs) (y:ys) | x /= y    = czyRozne xs ys
                       | otherwise = False

Tylko po co się rozdrabniać? Można np. tak:

czyRozne1 xs ys = all id $ zipWith (/=) xs ys
czyRozne2 xs ys = False `notElem` zipWith (/=) xs ys
0

Pisałem z palca. Nie chciało mi się myśleć ani testować ;P

1 użytkowników online, w tym zalogowanych: 0, gości: 1