Get index of next smallest element in the list in Haskell

minListIndex :: (Ord a, Num  a) => a -> [a] -> a

The problem is that you are trying to return result of generic type a but it is actually index in a list.

Suppose you are trying to evaluate your function for a list of doubles. In this case compiler should instantiate function's type to Double -> [Double] -> Double which is nonsense.

Actually compiler notices that you are returning something that is derived from list's length and warns you that it is not possible to match generic type a with concrete Int.

length ys returns Int, so you can try this instead:

minListIndex :: Ord a => a -> [a] -> Int

Regarding your original problem, seems that you can't solve it with plain recursion. Consider defining helper recursive function with accumulator. In your case it can be a pair (min_value_so_far, its_index).


First off, I'd separate the index type from the list element type altogether. There's no apparent reason for them to be the same. I will use the BangPatterns extension to avoid a space leak without too much notation; enable that by adding {-# language BangPatterns #-} to the very top of the file. I will also import Data.Word to get access to the Word64 type.

There are two stages: first, find the index of the given element (if it's present) and the rest of the list beyond that point. Then, find the index of the minimum of the tail.

-- Find the 0-based index of the first occurrence
-- of the given element in the list, and
-- the rest of the list after that element.
findGiven :: Eq a => a -> [a] -> Maybe (Word64, [a])
findGiven given = go 0 where
  go !_k [] = Nothing --not found
  go !k (x:xs)
    | given == xs = Just (k, xs)
    | otherwise = go (k+1) xs

-- Find the minimum (and its index) of the elements of the
-- list greater than the given one.
findMinWithIndexOver :: Ord a => a -> [a] -> Maybe (Word64, a)
findMinWithIndexOver given = go 0 Nothing where
  go !_k acc [] = acc
  go !k acc (x : xs)
    | x <= given = go (k + 1) acc xs
    | otherwise
    = case acc of
        Nothing -> go (k + 1) (Just (k, x)) xs
        Just (ix_min, curr_min)
          | x < ix_min = go (k + 1) (Just (k, x)) xs
          | otherwise = go (k + 1) acc xs

You can now put these functions together to construct the one you seek. If you want a general Num result rather than a Word64 one, you can use fromIntegral at the very end. Why use Word64? Unlike Int or Word, it's (practically) guaranteed not to overflow in any reasonable amount of time. It's likely substantially faster than using something like Integer or Natural directly.