I have this date type:
data Storage = HDD String Int Int | SSD String Int deriving (Eq, Show)
HDD (Producer) (RPM) (Capacity) | SSD (Producer) (Capacity)
My task is to list all the HDDs which are larger than the biggest SSD capacity wise (if there are no SSDs, then list all the HDDs) , in this function:
hugeHDDs :: [Storage] -> [Storage]
This was my try on creating the functions which give the largest capacity of the SSDs:
maxSSD :: [Int] -> Int
maxSSD = foldr f 0
where f a (cap (SSD c b)) = max a (cap (SSD c b))
cap :: Storage -> Int
cap (SSD _ b) = b
But it doesn't work and even if it would, I don't really know how to move on
CodePudding user response:
Since this is homework, my preference would be to nudge you rather than give you the full answer. Let's start by looking at the "it doesn't work" part:
maxSSD :: [Int] -> Int
maxSSD = foldr f 0
where f a (cap (SSD c b)) = max a (cap (SSD c b))
Then let's look at the foldr signature:
foldr :: (a -> b -> b) -> b -> [a] -> b
You're looking to take an [Int]
and reduce to an Int
. Based on your function name, you're hoping to feed in the list of SSD capacities and find the smallest one.
Where I think you've gone slightly off the rails is that the function that you are feeding the foldr is suddenly trying to deal with SSD
types, when it doesn't have one to begin with. If you want to create an SSD, you'll need to feed it a producer and a capacity. You have a constructor for an SSD in your f
function, but what are you putting into the constructor?
SSD c b
Syntactically, that's valid haskell, but if c and b aren't defined, then the compiler is going to complain. If they are defined, they will always be the same. That means they won't help you at all in the function you've written.
You might think about this problem in a different way:
Think about what you want to get from the maxSSD
function. You want to take a list of SSD's, and if there are no SSD's, then there's no max. If there are SSD's, get the capacity of the highest one.
That says your function signature might look more like:
maxSSD :: [SSD] -> Int
Idiomatically, it might be better to use maxSSD :: [SSD] -> Maybe Int
, but we can keep this simple for now.
As you implement this function, you might writing it first with simple recursion:
maxSSD [] = 0
maxSSD ((SSD _ cap):xs) = ...
and then use foldr only when you understand the recursion explicitly.
CodePudding user response:
The task looks like this (it's now "working")
data Storage = HDD String Int Int | SSD String Int deriving (Eq, Show)
capacity :: Storage -> Int
capacity (HDD _ _ a) = a
capacity (SSD _ b) = b
isHDD :: Storage -> Bool
isHDD (HDD _ _ _) = True
isHDD (SSD _ _) = False
maxSSD :: [Storage] -> Int
maxSSD [] = 0
maxSSD [(SSD _ c)] = c
maxSSD [(HDD _ _ _)] = 0
maxSSD (x:xs)
|(capacity x >= capacity (head xs)) && ((isHDD x) == False) && ((isHDD (head xs)) == False) = maxSSD (x:(tail xs))
|otherwise = maxSSD xs
hugeHDDs :: [Storage] -> [Storage]
hugeHDDs [] = []
hugeHDDs (x:xs)
|(isHDD x == True) && ((capacity x) > (maxSSD xs)) = (x:(hugeHDDs xs))
|otherwise = hugeHDDs xs