Using filter on an item in a list?
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 Car
s. 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 -> Int
name :: Film -> String
- and so forth
See also LYAH # Record syntax
The point is this:
[putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase]
You haven't understood list comprehension yet. What you want is:
[ (Car w x y z) | (Car w x y z) <- testDatabase, y==choosenYear]
Probably.
With
mapM (putStrLn . formatCarRow)
you have already ordered: format and then print each element of the follwoing list. Hence, the putStrLn in the list comprehension is utterly absurd.
Please note that putStrLn is in some way a misnomer: It won't print anything actually! It just constructs a thing that happens to cause printing when executed in the IO monad. It seems like this is hard to understand, but soon you will.
精彩评论