I've been doing project euler problems in Haskell, and often I've found the need to get the value that gives the maximum of a function.
For example,
answer = argmaximum $ map collatzLength [1..10^6]
Where collatzLength is a previously defined function.
I came up with this code, which is heavily influenced by learning Ocaml. I run a helper function that has variables that keep track of the best value index and best index so far. It works perfectly for positive lists, but it seems like there's a better way.
Is there a less clunky way to implement argmaximum?
argmaximum :: (Ord a, Num a) => [a] -> a
argmaximum lst = helper lst 0 0 0 where
helper (x:xs) current bestVal bestIndex
| current > bestVal = helper xs (current + 1) x current
| otherwise = helper xs (current + 1) bestVal bestIndex
helper null _ _ bestIndex = bestIndex
1 Answer 1
What you have implemented here is strictly speaking not argmaximum, but finding a maximum index in a list. The difference is that your argmaximum will not return the correct value for invocations that don't map
from [1..?]
Instead of that, you probably wanted something that's typed as follows:
argmax :: (Ord a, Num a) => (b -> a) -> [b] -> b
argmax f (d:ds) = ...
That way you can write argmax collatzLength [500..10^6]
and still get the correct answer :)
By the way: @cole suggested using maximumBy
and comparing
for the implementation, which I wholeheartedly agree on :)
maxmimumBy (comparing collatzLength) [1..10^6]
ormaximumBy (compare `on` collatzLength) [1..10^6]
. I’m not sure I understand how your function works, unlesscurrent > bestVal
is a typo and meant to bex > bestVal
. It’s late so I’m afraid I cannot review more thoroughly - I do hope at least one of my suggestions type checks. \$\endgroup\$