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