【问题标题】:Find max element and index of a list in Haskell在 Haskell 中查找列表的最大元素和索引
【发布时间】:2013-01-11 02:35:44
【问题描述】:

我正在迈出进入 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 在返回最大元素的值后似乎挂起。

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

我大胆猜测这与 Haskell 的惰性求值性质有关,但我发现很难弄清楚这里到底发生了什么,以及如何解决它。我也非常感谢任何人关于如何在 Haskell 中调试的任何提示。有没有一种简单的方法可以在执行期间打印出值而不影响行为?

我只是想指出,我知道有几种更好的方法可以使用内置的 Haskell 函数来获得这种行为。我正在从头开始实现它以尝试学习 Haskell。

谢谢

【问题讨论】:

    标签: haskell ghci


    【解决方案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 的值,这就是为什么您的版本即使无法计算索引也可以成功计算最大值的原因。

    调试纯计算的标准方法是Debug.Trace 模块。

    附带说明,有一个更简单的解决方案:

    import Data.List
    import Data.Ord
    
    maxi xs = maximumBy (comparing fst) (zip xs [0..])
    

    编辑:哎呀,我没有看到你故意从头开始实现它,但我还是把它留在那里。

    【讨论】:

    • 我认为从头开始实现maximumBycomparingzip 也是一个很好的练习。它还说明了如何设计模块化程序。
    【解决方案2】:

    我看到您的问题已经得到解答。我设法在没有递归的情况下使用 lambda 函数做到了。

    maxim xs = foldr (\ (x,y) acc -> if (x == maximum xs) then (x,y) else acc) (0,head xs) (zip xs [0..])
    

    【讨论】:

      猜你喜欢
      • 2010-12-02
      • 2020-12-05
      • 1970-01-01
      • 2021-04-20
      • 1970-01-01
      • 2021-07-02
      • 2021-11-07
      • 2013-04-17
      相关资源
      最近更新 更多