Найти 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: Ой, я не видел, что вы намеренно внедряете его с нуля, но я все равно оставлю это там.