How to remove [ ] from testDatabase

Viewed 55

How to fix this error? I know that testDatabase have an additional [ ] but how to remove the [ ] without triggering error? I am stuck for a few days...

* Couldn't match expected type `Spa -> [Spa]'
              with actual type `[Spa]'
* In the second argument of `(.)', namely `testDatabase'
  In the second argument of `(.)', namely
    `averageRating . testDatabase'
  In the first argument of `filter', namely
    `((>= 8) . averageRating . testDatabase)'

My code below

data Spa = Spa SpaID Brand Area Stars [(Service, LevelRating)]
                  deriving (Eq, Show, Read)

type spaID = String
type Brand = String
type Area = String
type Stars = Int
type Service =  String 
type LevelRating = Int 

testDatabase :: [Spa]

-- spa service level rating
getServiceLevelRating :: Spa -> [(Service, LevelRating)]
getServiceLevelRating (Spa _ _ _ _ s) = s

--making spa average level rating
averagelvRating :: [(String,Int)] -> Float
averagelvRating [] = 0
averagelvRating avglvrating = (fromIntegral(sum $ map snd avglvrating)) / (fromIntegral(length avglvrating))

--making spa average list
averageRating :: [Spa] -> [Float]
averageRating = (<$>) (averagelvRating . getServiceLevelRating)

--filtering
spaLevelRating :: Float -> [Spa] -> [Spa]
spaLevelRating levelRating = filter ((>=8) . averageRating . testDatabase)
2 Answers

You are using composition (.) with non-function operand testDatabase. You probably meant

spaLevelRating levelRating = filter ((>=8) . averageRating) testDatabase

Use fmap instead of (<$>) if you're not going to use it as an infix operator:

averageRating = fmap (averagelvRating . getServiceLevelRating)

or simply map to make it clear that we mean the list functor. Since getServiceLevelRating is a field getter, you may want to use record syntax to get them as native parts of the data type. And since we're doing averages on integers, the div operator avoids the need for fromIntegral.

import Data.List (genericLength)

data Spa = Spa
  { spaID :: SpaID
  , spaBrand :: Brand
  , spaArea :: Area
  , spaStars :: Stars 
  , spaServiceLevelRating :: [(Service, LevelRating)]
  } deriving (Eq, Show, Read)

average :: Integral a => [a] -> a
average xs = sum xs `div` genericLength xs

averageLevelRating :: Spa -> LevelRating
averageLevelRating = average . map snd . spaServiceLevelRating

This way average is a little more reusable and filtering becomes

filter ((>= 8) . averageLevelRating) testDatabase
Related