Haskell 除数
我遇到了一个问题,我想了解更多信息以及如何避免。我有这段代码
len :: (Num r ) => [a] -> r
len [] = 0
len xs = 1 + len ( tail xs )
avg :: (Num t) => [t] -> Double
avg xs = ( sum xs ) / ( len xs )
,它呈现以下错误
len.hs:6:9: Couldn't match expected type `Double' against inferred type `t' `t' is a rigid type variable bound by the type signature for `avg' at len.hs:5:12 In the expression: (sum xs) / (len xs) In the definition of `avg': avg xs = (sum xs) / (len xs)
现在,我知道这个错误(感谢 irc.freenode.net#haskell)是除法函数的结果
(/) :: (Fractional a) => a -> a -> a
但是,我不知道该怎么办。我的 avg 函数签名应该与除法运算符的怪癖无关(需要 Fractional 类型类)。因此,我认为克服这个问题的正确方法是转换为实现分数类型的类型,但我不知道如何实现,或者即使这是正确的?有什么想法吗?
I'm having an issue I want to learn more about, and how to avoid. I've got this code
len :: (Num r ) => [a] -> r
len [] = 0
len xs = 1 + len ( tail xs )
avg :: (Num t) => [t] -> Double
avg xs = ( sum xs ) / ( len xs )
Which renders the following error
len.hs:6:9: Couldn't match expected type `Double' against inferred type `t' `t' is a rigid type variable bound by the type signature for `avg' at len.hs:5:12 In the expression: (sum xs) / (len xs) In the definition of `avg': avg xs = (sum xs) / (len xs)
Now, I know this error (thanks to irc.freenode.net#haskell) is a result of the division function
(/) :: (Fractional a) => a -> a -> a
However, I don't know what to do. My avg
function signature should have nothing to do with the division opperators quirks (requiring Fractional
typeclass). So, I'm left thinking the right way to overcome this is by casting to a type that impliments they Fractional
typeclass but I have no idea how, or even if this is right? Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
为什么会这样?如果您想计算一堆整数的平均值,则必须在某个时刻进行除法,因此您必须将它们从整数转换为您选择的支持除法的类型。仔细观察
Num
类(ghci 中的:i Num
)揭示了avg
类型的一个问题:Num 没有足够的方法——基本上足以进行加法、乘法和减法。根本无法保证我提供给
avg
的数字可以转换为Double
。如果您输入一个无类型函数来计算平均值,Haskell 会以最通用的类型进行响应:
这就是
avg
的正确类型。您可能会注意到
avg [1,2,3 :: Integer]
给出类型错误。您可以通过首先将参数传递给toRational
或fromIntegral
来解决这个问题,它们使用Real
和Integral
实例分别为Integer
。关于表达式
sum [1,2,3] / len [1,2,3]
:确实,像1
这样的文字数字具有类型数字a => a
,它会在任何类型上调用fromInteger
,但像1/2
这样的表达式具有更具体的Fractional a 类型=> a
,如果您询问该表达式的类型而不是打印出来,您就可以看到它。ghci 中的
:set -Wall
可能会有所帮助,每当为您选择默认类型时,它都会打开大量警告,提示最通用的类型可能不再正确。Why is that? If you want to compute the average of a bunch of Integers, you'll have to divide at some point, so you'll have to convert them from Integers to the division-supporting type of your choice. A close look at the
Num
class (:i Num
in ghci) reveals one problem with the type ofavg
:Num
doesn't have enough methods — basically enough to add, multiply, and subtract. There's no guarantee that the number I give toavg
can be converted to aDouble
at all.If you enter an untyped function to compute an average, Haskell responds with the most generic type possible:
So that's the correct type of
avg
.You might notice that
avg [1,2,3 :: Integer]
gives a type error. You can get around that by passing the argument totoRational
orfromIntegral
first, which use theReal
andIntegral
instances forInteger
, respectively.Regarding the expression
sum [1,2,3] / len [1,2,3]
: It's true that a literal number like1
has the type ofNum a => a
, which callsfromInteger
on whatever type it turns out to be, but an expression like1/2
has a more specific type ofFractional a => a
, which you can see if you ask for the type of that expression instead of printing it out.Something that might be helpful is
:set -Wall
in ghci, which turns on lots of warnings whenever a default type is chosen for you, giving a clue that the most generic type might no longer be correct.您过度限制 avg 的类型。使用更通用的版本, avg :: (Fractional a) => [一]->一个
You're overly constraining the type of avg. Use the more general version, avg :: (Fractional a) => [a] -> a
hhm 真正的问题是,如果它是整数类型,您想将其转换为小数类型,但如果它是小数类型,您想不理会它。
试试这个
hhm the really problem is if it is an integral type you want to cast to a fractional type, but if it is an fractional type you want to leave it alone.
Try this
我遇到过这个问题。我所做的最好的事情是有两个求平均值的函数:一个用于积分,一个用于分数:
I've encountered this problem. This best I've managed to do is have two functions for averaging: one for integrals and one for fractionals: