I am attempting to take a list of lists and print the maximum value found amongst all the lists. I have a function I believe should work, but I believe the way I am declaring the values is causing a problem.
nested_max :: [[Int]] -> Int
nested_max [] = minBound::Int
nested_max [[x]] = x
nested_max [[x,xs]] = nested_helper [[x,xs]]
nested_helper [[x,xs]]= maximum (concat[[x,xs]])
Any help is appreciated.
CodePudding user response:
All patterns except the first one match with a singleton list: a list with one element. In that list you match again with a singleton list (so a list with one element that is a list with one element), and a list with two elements).
But you thus do not match with a list with an arbitrary number of sublists, nor with a list that has as first list a list with zero or more than two elements.
You however do not need to pattern match on the list, you can work with:
nested_max :: [[Int]] -> Int
nested_max = helper . concat
where helper [] = minBound
helper xs = maximum xs
We thus first concatenate the list of lists into a single list, then we check if that list is empty, in which case we return minBound
, or we return maximum xs
which will return the maximum of the elements.
CodePudding user response:
The problem is the declaration [[x,xs]]
, which is a list, which contains a list of two elements. This is not what you want, as it is not the general case - at some point you need the general case to match everything that you haven't matched yet.
You could try lst:lsts
which matches the first element, the head, against lst
and the other elements (if any) against lsts
- this is the standard technique for recursion. We are not doing recursion here, so we can ignore this.
You could try nlsts
which matches the list of lists in one go. Since you are passing one item to nested_helper
and concat
this seems to be the more natural and correct thing to do.
Thus:
nested_max :: [[Int]] -> Int
nested_max [] = minBound::Int
nested_max [[x]] = x
nested_max nlsts = nested_helper nlsts
nested_helper nlsts = maximum (concat nlsts)
For completeness, there is a recursive version. This uses the lst:lsts
form:
nested_max_new :: [[Int]] -> Int
nested_max_new [[]] = minBound
nested_max_new nlst = maximum (nested_helper_new nlst)
nested_helper_new :: [[Int]] -> [Int]
nested_helper_new [] = []
nested_helper_new (lst:nlst) = (maximum lst) : nested_helper_new nlst
Finally, in practical code we try to use map
, filter
and reduce
- it doesn't much matter which functional language it is. This tends to provide the simplest and most readable code:
nestedMax :: [[Int]] -> Int
nestedMax nlst = maximum (map (\x -> maximum x) nlst)
NB: Like so many of Haskell's base functionality, maximum
is a partial function, it doesn't work for all inputs. So you might prefer:
maxList::[Int] -> Int
maxList [] = minBound
maxList lst = maximum lst