【问题标题】:A function that returns maximum of list and count of occurrences返回列表最大值和出现次数的函数
【发布时间】:2017-03-18 19:43:41
【问题描述】:

我正在编写一个递归函数mxAndC。当我给它一个列表时,它应该返回一个元组。元组将给定列表的最大值作为其第一个元素,第二个元素将是该元素在列表中出现的次数。赋值不允许我创建辅助函数。我期待以下输出:

mxAdC "bananas" = (s,1)

mxAdC "banana" =(n,2)

mxAdC [mod x 4 | x <- [1..50]] -> (3,12)

我做了以下事情:

mxAdC = go 0
 where go count (x:xs)  
           | count /= 0      = (mx, count)
           | null ((x:xs))   = error "The list is empty"
           | x == mx         = go (count+1) xs
         where mx = maximum (x:xs)

我得到了错误:

* Ambiguous type variable `a0' arising from a use of `go'
      prevents the constraint `(Ord a0)' from being solved.
      Relevant bindings include
        mxAdC :: [a0] -> (a0, Integer) (bound at hw06.hs:24:1)
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instances exist:
        instance (Ord a, Ord b) => Ord (Either a b)
          -- Defined in `Data.Either'
        instance Ord Ordering -- Defined in `GHC.Classes'
        instance Ord Integer
          -- Defined in `integer-gmp-1.0.0.1:GHC.Integer.Type'
        ...plus 23 others
        ...plus 38 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    * In the expression: go 0
      In an equation for `mxAdC':
          mxAdC
            = go 0
            where
                go count (x : xs)
                  | count /= 0 = (mx, count)
                  | null ((x : xs)) = error "The list is empty"
                  | x == mx = go (count + 1) xs
                  where
                      mx = maximum (x : xs)

我是 Haskell 的新手。有哪位仁慈的专家愿意伸出手来帮助这个新手吗?

【问题讨论】:

  • 你应该为你的函数添加类型签名。
  • @duplode:我认为这并不是真正的重复。另一个问题有一个矛盾类型,这个问题原则上是合理的,但有一个单态限制问题。相同的错误消息,但根本问题完全不同。
  • @duplode 您提到的与我的问题重复的问题并没有真正解决我的问题,尽管它们有相同的错误消息。请重新阅读我的问题。谢谢。
  • @leftaroundabout 确实。关闭投票撤回,然后。

标签: haskell recursion functional-programming higher-order-functions


【解决方案1】:

你达到了可怕的单态限制。

您可以通过

修复类型错误
  • 使用mxAdC x = go 0 x
  • {-# LANGUAGE NoMonomorphismRestriction #-} 放在文件的开头
  • 添加类型签名

你的函数仍然是错误的,但现在它会进行类型检查。

Haskell 禁止看起来像顶级常量的多态函数(在= 符号之前没有参数)。所以一般来说你不能 eta-reduce(用 foo = bar 替换 foo x = bar x)。完整的解释相当长 - 请参阅此答案:https://stackoverflow.com/a/32496865/805266

【讨论】:

  • 对,但是 a) 这绝对不是解决方案的优先顺序 b) 答案可以使用更多解释。跨度>
  • 把 {-# LANGUAGE NoMonomorphismRestriction #} 仍然给出错误。
  • @AliToto 不,不是。好吧,至少它没有给出您所询问的错误
  • 我好像忘记了-。这是{-# LANGUAGE NoMonomorphismRestriction #-}
【解决方案2】:

一个相当简单的实现将使用filter

mxAdC :: Ord a => [a] -> (a,Int)
mxAdC xs = (mx,length $ filter (\x -> x == mx) xs) where mx = maximum xs

【讨论】:

  • 您的意见是什么?
  • 这很奇怪,无法复制将上面的确切代码粘贴到空白文件中。您确定编译器错误与这些行有关吗?尝试粘贴到空白文件中。
  • 我想说这不是一个有效的解决方案,因为它需要额外一轮相当不必要的相等比较加上length(这通常有点代码味道)。此外,它会评估 maximum xs 两次。因此,OP 的原始方法实际上更好,尽管它的手动递归有些行人。 (仔细想想,这个解决方案实际上并没有太糟糕——只是应该避免重复使用maximum xs)。
  • 删除了maximum的重复计算。额外一轮相等比较是什么意思?
  • 为作业提供完整的解决方案有点不公平
【解决方案3】:

其他人已经解释了类型错误。让我们看看更有趣的错误。

  | null ((x:xs))   = error "The list is empty"

怎么了? x : xs 永远不会为空。不可能,因为它的第一个元素是x!你在这里的意思是

mxAdC ys
  | null ys = error "mxAdC: the list is empty"
  | otherwise = go 0 ys
  where ...

下一个问题是

  | count /= 0      = (mx, count)

这表示只要计数不为零,您就完成了。所以你永远不会超过 1。你认识到你的递归需要一个基本情况,所以你试图放入一个,但你错过了标记。您需要的基本情况是处理空列表:

go count [] = ?
go count (x:xs)  
  | x == mx         = go (count+1) xs

但是,go 仍然缺少一些东西。 x /= mx时你想发生什么?您需要再添加一个案例(我留了问号让您填写):

go count [] = ?
go count (x:xs)  
  | x == mx         = go (count+1) xs
  | otherwise       = ?

最后一个主要问题是您在go 函数中定义了mx。这将计算每次提交的列表go 的最大值。你要做的是在mxAdC中定义mx

mxAdc ys
  | ....
  where
    go ...
    mx = maximum ys

还有两个大的效率问题需要处理。一个问题是go 不再强制在递归调用中计算累加器,这可能会导致空间泄漏。使用BangPatterns 语言扩展很容易解决这个问题

go !count [] = ?
go !count (x:xs)  
  | x == mx         = go (count+1) xs
  | otherwise       = ?

最后一个问题是您仍然遍历列表两次:一次计算最大值,然后再次计算它出现的次数。只需一次即可完成。我不会给你所有的细节,但基本的技巧是改变你的go 函数来获取迄今为止看到的最大元素以及它被看到的次数。您必须调整 mxAdC 的其余部分以适应,使用模式匹配而不是 null

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    • 2016-07-19
    • 1970-01-01
    • 2018-05-08
    相关资源
    最近更新 更多