我正在写一个递归函数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的新手。在那里,任何仁慈的专家是否愿意伸出手来帮助这个新手?
答案 0 :(得分:0)
你遇到了可怕的单态限制。
您可以通过
修复类型错误mxAdC x = go 0 x
{-# LANGUAGE NoMonomorphismRestriction #-}
放在文件的开头你的功能仍然是错误的,但现在却出现了问题。
Haskell禁止看起来像顶级常量的多态函数(在=
符号之前没有参数)。所以通常你不能eta-reduce(用foo x = bar x
替换foo = bar
)。完整的解释相当长 - 请参阅此答案:https://stackoverflow.com/a/32496865/805266
答案 1 :(得分:0)
相当简单的实现将使用filter
:
mxAdC :: Ord a => [a] -> (a,Int)
mxAdC xs = (mx,length $ filter (\x -> x == mx) xs) where mx = maximum xs
答案 2 :(得分:0)
其他人已经解释了类型错误。让我们来看看更有趣的错误。
| 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 = ?
最后一个主要问题是您在mx
函数中定义了go
。这将计算每次递送列表go
的任何部分的最大值。您要做的是在mx
mxAdC
mxAdc ys
| ....
where
go ...
mx = maximum ys
还有两个很大的效率问题需要处理。一个问题是go
不再强制在递归调用中计算累加器,这可能导致空间泄漏。使用{/ 1}}语言扩展名
BangPatterns
最后一个问题是您仍然遍历列表两次:一次计算最大值,然后再次计算它发生的次数。只需一次就可以完成。我不会给你所有的细节,但基本的诀窍是改变你的go !count [] = ?
go !count (x:xs)
| x == mx = go (count+1) xs
| otherwise = ?
函数,以获取迄今为止看到的最大元素以及它被看到的次数。你必须调整go
的其余部分才能适应,使用模式匹配来取代mxAdC
。