Reputation: 176
My function rtnDryPlaces is supposed to return a list of all dry places if they were dry on a particular day - with day 1 being yesterday (last element) and day 7 being last week (first element).
type Name = String
type Location = (Float,Float)
type RainfallFigures = [Int]
type Place = (Name,Location,RainfallFigures)
testData=[("London", (51.5, -0.1), [0, 0, 5, 8, 8, 0, 0]),("Cardiff", (51.5 , -3.2),[12, 8, 15, 0, 0, 0, 2])]
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ((a,(b,c),d):xs) n
| d == [] = []
| (reverse d)!!n-1 == 0 = a:rtnDryPlaces xs n
demo 4 = print (rtnDryPlaces testData 2 )
The second guard reverses the list and returns the element at that index (index is day). If it returns 0, then the name a is appended to the list of names which have also returned 0 for that day. When the test data runs out, so does the rainfall data so I've set the stop condition to be when d = []
Upvotes: 1
Views: 60
Reputation: 476699
One of the problems is that the recursive calls will eventually reach the empty list, and you did not define a result for that:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces [] _ = []
rtnDryPlaces ((a,(b,c),d):xs) n
| d == [] = []
| (reverse d)!!n-1 == 0 = a:rtnDryPlaces xs n
But even then it will not work (yet). For example (reversed d)!!n-1
is interpreted as ((reverse d)!!n)-1
, so it first takes the element at index n
, and then it will subtract that element with 1
. It will not take the n-1 element.
Furthermore if the (reversed d)!!(n-1)
is not zero, then that guard will not "fire", and thus we get again an exhaustive pattern failure. We thus should add an otherwise
at the end:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces [] _ = []
rtnDryPlaces ((a,_,d):xs) n
| d == [] = []
| (reverse d)!!(n-1) == 0 = a:rtnDryPlaces xs n
| otherwise = rtnDryPlaces xs n
Now this will give us a result:
Prelude> rtnDryPlaces testData 2
["London","Cardiff"]
But we can still make this more elegant by making use of filter
and map
:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ps n = map (\(x,_,_) -> x) (filter p ps)
where p (_,_,d) | (0:_) <- drop (n-1) (reverse d) = True
| otherwise = False
or as @DanielWagner says, with list comprehension:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ps n = [p | (p, _, d) <- ps, 0 <- take 1 . drop (n-1) . reverse $ d]
Here the take 1 . drop (n-1)
will make a singleton list (given the list has enough elements) with the amount of rain for that day. If that then pattern matches with 0
, we will yield p
in the result. If the value for that day does not match with 0
, or the list has not enough elements (then take 1 . drop (n-1) (reverse d)
will yield an empty list), then that element is not emitted in the result.
Upvotes: 2