Filtering elements from a List of a created Data Type in haskell

Viewed 354

I am new to haskell & i was trying to filter elements from a created Data Type called Hoover.

Now a Hoover has a Price & a Wattage , I defined Hoover as :

data Hoover = HH Price Wattage

& Price & Wattage as :

data Price = P Int 
data Wattage = W Int 

When i try to run this code for filtering the hoovers from a catalog of differently priced Hoovers :

(Here m is the minimum price and n is the maximum price) :

filterProduct :: Price -> Price -> [Hoover] -> [Hoover]
filterProduct (P m) (P n) [] = []
filterProduct (P m) (P n) (x:xs) = if(price >= m && price <= n) then ([x] ++ (filterProduct (P m) (P n) xs))
                                    else (filterProduct (P m) (P n) xs)

where
 x :: Hoover 
 x = HH (P price) watt

I get quite a lot of errors, i tried to do a lot of things but couldn't get around it & needed help fixing it

Would appreciate any help !

2 Answers

In your program, price seems to appear out of "thin air". You do not define it in the head of the expression (before the =). So the compiler does not understand what you are doing.

You actually wrote the where caluse in the wrong way. The pattern is placed at the left side of the equation, so:

filterProduct :: Price -> Price -> [Hoover] -> [Hoover]
filterProduct (P m) (P n) [] = []
filterProduct (P m) (P n) (x:xs) = if(price >= m && price <= n) then ([x] ++ (filterProduct (P m) (P n) xs))
                                    else (filterProduct (P m) (P n) xs)

    where HH (P price) watt = x

That being said, you make things too hard. You can make use of the filter :: (a -> Bool) -> [a] -> [a] function here to filter your list:

filterProduct :: Price -> Price -> [Hoover] -> [Hoover]
filterProduct (P m) (P n) = filter (\(HH (P price) watt) -> price >= m && price <= n)

It furthermore might make more sense to define a type synonym with:

type Price = Int
type Wattage = Int

if you do not plan to define special type class instances on these types.

Willem Van Onsem's answer is splendid as always, and it seems to have resolved your issue. I'd still like to put forth another approach, using record syntax:

data Hoover = HH
    { hooverPrice   :: Int
    , hooverWattage :: Int
    }

If you declare your type like this, it'll give you two functions hooverPrice and hooverWattage of type Hoover -> Int.

Now, if you have a function that can check whether an Int is within your desired price range, you need only compose that function with hooverPrice, and you'll have a function that checks whether a vacuum cleaner's price falls within that range. Armed with this function, the problem is reduced to a simple filter.

Related