Reputation: 667
newtype Name = Name String deriving (Show)
newtype Age = Age Int deriving (Show)
newtype Weight = Weight Int deriving (Show)
newtype Person = Person (Name, Age, Weight) deriving (Show)
type Gym = [Person]
isAdult :: Person -> Bool
isAdult (Person (_, Age a, _)) = a > 18
w = Person (Name "Lee", Age 30, Weight 120)
p = Person (Name "John" , Age 65, Weight 80)
updateWeight :: Person -> Int -> Person
updateWeight (Person (n, a, Weight w)) b = Person (n, a, Weight $ w + b)
getWeight :: Person -> Int
getWeight (Person (a, b, Weight c)) = c
getAge :: Person -> Int
getAge (Person (a, Age b, c)) = b
I was now thinking of trying find the average weight of people in the Gym between two ages.
So far I've got
getAverage:: Gym -> (Int, Int) -> Int
getAverage a (b,c) = sum . map getWeight . filter ((b >= age && c <= age) || (b <= age && c >= age))
where
age = getAge a
Upvotes: 1
Views: 190
Reputation: 54058
What you have is close, but not quite there. I would recommend breaking down the problem into sub-expressions and use a where
or let
local binding to make it more clear what you want to do:
getAverage :: Gym -> (Int, Int) -> Double
getAverage gym (minAge, maxAge) = fromIntegral total / fromIntegral count
where
isInAgeRange person = minAge <= age && age <= maxAge where age = getAge person
validPeople = filter isInAgeRange gym
total = sum $ map getWeight validPeople
count = length validPeople
From this point on, you could combine some of these lines to shorten the code, but this is incredibly readable, it won't suffer from many efficiency problem (although you can calculate the sum and the count at the same time with a fancy fold), and it doesn't take too many lines to write as it is.
Upvotes: 2