I have a function in Haskell which finds the maximum value of an exponentiation from a list:
prob99 = maximum $ map (\\xs -> (head xs)^(head (tail xs))) n
As a novice Haskeller that I am, I would think along these lines:
zip [0..] xs
. (Note that Haskell indexing starts from zero, i.e. the head of a list is x !! 0
.)I want to find the maximum of this zipped list [(0, x!!0), (1, x!!1), ..., (n, x!!n)]
according to the second element of each tuple. There are a few alternatives, based on how well I know Haskell:
maximumBy (comparing snd)
, if I only knew that these functions exist.maximumBy
exists but I suspected something like this, so I could search for it on Hoogle based on the type signature that I would use: it returns an element of type generic type a
from a list of a
elements, using a comparison function on two a
parameters (a -> a -> Ordering
) – altogether it would be either [a] -> (a -> a -> Ordering) -> a
, or some more logical permutation of the arguments. Thinking of it, putting the list as the penultimate argument makes more sense, because then it allows for better currying as we'll see in a moment, so let's search for (a -> a -> Ordering) -> [a] -> a
.import Data.List (foldl1')
maxBySnd :: Ord a => [(Int, a)] -> (Int, a)
maxBySnd = foldl1 cmpBySnd
where
cmpBySnd (i, xi) (j, xj) = case xi `compare` xj of
LT -> (j, xj)
_ -> (i, xi)
foldl1'
starts folding from the left (meaning the accumulator is on the left in the folding function), and the accumulated index is updated only if xj
is greater than xi
, so this will return the index of the first maximum. If one has a grudge against importing Data.List
and doesn't work with 1000-item-long lists, then foldl1
from Prelude will do just fine. The Data.Vector
package uses a similar approach, just search for “maxIndex
” here and here.
Ord
for comparable objects, in which case cmpBySnd
would become cmpBySnd (i, xi) (j, xj) = if xi < xj then j else i
At this point one would be missing out on the benefits of algebraic data types and higher-order functions (which fact is almost impossible to realize if one doesn't know), so 1) it's good that you're asking! 2) may I point the next reader to a resource like Learn You A Haskell For Great Good, or Real World Haskell, or this SO answer, or this GitHub repo.
(i, xi)
tuple, preferably with the built-in function fst :: (a, b) -> a
, or with the home-made function first (a,b) = a
The end result is the following:
import Data.List (maximumBy)
import Data.Ord (comparing)
maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . zip [0..]
-- or
-- maxIndex = fst . maxBySnd . zip [0..]