Найти max элемент и индекс списка в Haskell

Я делаю первые шаги в удивительный мир Хаскелла. В качестве упражнения, я бы хотел, чтобы реализовать метод, который находит максимальный элемент и его индекс. Назовем эту функцию "maxi". Вызов maxi в списке должен возвращать следующий результат:

ghci> maxi [1, 3, 4, 1, 2, 3]
(4, 2)

4 является самым большим int в этом списке, и он расположен в индексе 2.

Я попытался реализовать эту функцию следующим образом:

maxim :: (Ord a) => [a] -> (a, Int)
maxim l = 
  let pmaxim :: (Ord a) => [a] -> Int -> (a, Int) -- Internal function to do the work
      pmaxim [] _  = error "Empty list"           -- List is empty, error
      pmaxim [x] xi = (x, xi)                     -- List has one item, return it and the index
      pmaxim (x:xs) xi                            -- More than one item, break list apart
        | x > t     = (x, xi)                     -- If current item is bigger, return it and its index
        | otherwise = (t, ti)                     -- If list tail has a bigger item, return that
        where (t, ti) = pmaxim xs (ti + 1)        -- Get max of tail of the list
  in pmaxim l 0                                   -- Call internal function with start index

когда я называю это, я вам что-то действительно странное: ghci, похоже, зависает после возвращения значения элемента max.

ghci> maxi [1, 3, 4, 1, 2, 3]
(4,

Я рискну предположить, что это имеет какое-то отношение к ленивой природе оценки Хаскелла, но мне трудно понять, что на самом деле происходит здесь, и как это исправить. Я также буду очень благодарен за любые советы кого-нибудь о том, как отлаживать в Haskell. Есть ли простой способ распечатать значения во время выполнения без влияния на поведение?

I просто хотел отметить, что я знаю, что есть несколько лучших способов получить это поведение, используя встроенные функции Haskell. Я внедряю это с нуля, чтобы попытаться узнать Haskell.

спасибо

1 ответов


это из-за небольшой ошибки в коде. У вас есть:

where (t, ti) = pmaxim xs (ti + 1)

... но на самом деле это должно быть:

where (t, ti) = pmaxim xs (xi + 1)

это исправляет ваш код, который теперь производит правильное решение:

>>> maxim [1, 2, 3, 2, 1]
(3, 2)

ваш код повесили, потому что ваши вычисления для ti приводит к бесконечному циклу, так как вы случайно определили его в терминах себя. Обратите внимание, что ghc является достаточно умным компилятором и выясняет, что t не зависит от стоимости ti, поэтому ваша версия все еще может успешно вычислить максимальное значение, даже если она не может вычислить индекс.

стандартным способом отладки чистых вычислений является .

в качестве примечания, есть гораздо более простое решение:

import Data.List
import Data.Ord

maxi xs = maximumBy (comparing fst) (zip xs [0..])

Edit: Ой, я не видел, что вы намеренно внедряете его с нуля, но я все равно оставлю это там.