I am trying to filter by an item in a list and print them line by line. Here's my code:
data Car = Car String [String] Int [String]
testDatabase :: [Car]
testDatabase = [Car"Casino Royale" ["Daniel Craig"] 2006 ["Garry", "Dave", "Zoe", "Kevin", "Emma"],Car"Blade Runner" ["Harrison Ford", "Rutger Hauer"] 1982 ["Dave", "Zoe", "Amy", "Bill", "Ian", "Kevin", "Emma", "Sam", "Megan"]]
formatCarRow (Car a b c d) = show a ++ " | " ++ concat [i ++ ", " | i <- init b] ++ last b ++ " | " ++ show c ++ " | " ++ concat [j ++ ", " | j <- init d] ++ last d
displayFilmsByYear :: String -> IO [()]
displayFilmsByYear chosenYear = mapM (putStrLn.formatFilmRow) [putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase] -- This is the code not working i think
Why isnt this working?
If you wish to filter a list, I recommend using the filter function :)
data Car = Car String [String] Int [String]
year :: Car -> Int
year (Car _ _ y _) = y
filterByYear :: Int -> [Car] -> [Car]
filterByYear chosenYear cars = filter (\car -> year car == chosenYear) cars
showCar :: Car -> String
showCar car = undefined -- you can implement this how you like
displayCarsByYear :: Int -> IO ()
displayCarsByYear chosenYear = mapM_ (putStrLn . showCar) filteredCars
where filteredCars = filterByYear chosenYear testDatabase
It seems wise to explain a few things here:
Anonymous Functions: (\car -> year car == chosenYear) is an anonymous function. It takes one argument and calls it car. Then it determines whether that car's year is equal to the chosenYear. I didn't explicitly write this function's type signature, but it's Car -> Bool.
Filtering: I gave that function to filter, so that it would look through the list of Cars. When filter finds cars for which that function returns True, it puts them in the result list. A False result means that a car doesn't make it through the filter.
Function composition: (putStrLn . showCar) This is a function that first performs showCar, and then uses putStrLn on the result of showCar.
Where: You'll notice the where statement at the end of my code. It should be fairly self-explanatory, you can use either let or where statements to define "local variables". As a matter of taste, I prefer where over let.
List comprenensions vs filter: List comprehensions can filter a list just like the filter function. For a function f :: a -> Bool, and a list xs :: [a]
filter f xs is the same as [x | x <- xs, f x]. As a matter of taste, I prefer spelling out filter in such cases, since it makes it very clear that I'm filtering the list.
See also LYAH # Maps and filters
--
Further recommendation: use record syntax
Instead of
data Car = Car String [String] Int [String]
Why not
data Film = Film { name :: String
, actors :: [String]
, released :: Int
, characters :: [String]
}
(I couldn't really tell what your last list of Strings was)
This way, you can construct a Film like this:
lotr :: Film
lotr = Film { name = "Lord of the Rings"
, actors = ["Elijah Wood", "Ian McKellen", "Orlando Bloom"]
, released = 2001
, characters = ["Frodo", "Sam", "Pippin", "Merry"]
}
And you automatically have accessor functions
released :: Film -> Intname :: Film -> StringSee also LYAH # Record syntax
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With