Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 240
Ash Avatar asked Jan 30 '26 23:01

Ash


1 Answers

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 -> Int
  • name :: Film -> String
  • and so forth

See also LYAH # Record syntax

like image 160
Dan Burton Avatar answered Feb 01 '26 15:02

Dan Burton