Haskell 除数

发布于 2024-08-12 14:45:44 字数 772 浏览 4 评论 0原文

我遇到了一个问题,我想了解更多信息以及如何避免。我有这段代码

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苦行僧 2024-08-19 14:45:45

我的 avg 函数签名应该与除法运算符的怪癖无关

为什么会这样?如果您想计算一堆整数的平均值,则必须在某个时刻进行除法,因此您必须将它们从整数转换为您选择的支持除法的类型。仔细观察 Num 类(ghci 中的 :i Num)揭示了 avg 类型的一个问题:Num 没有足够的方法——基本上足以进行加法、乘法和减法。根本无法保证我提供给 avg 的数字可以转换为 Double

如果您输入一个无类型函数来计算平均值,Haskell 会以最通用的类​​型进行响应:

Prelude List> :type \x -> sum x / genericLength x
\x -> sum x / genericLength x :: (Fractional a) => [a] -> a

这就是 avg 的正确类型。

您可能会注意到 avg [1,2,3 :: Integer] 给出类型错误。您可以通过首先将参数传递给 toRationalfromIntegral 来解决这个问题,它们使用 RealIntegral 实例分别为Integer


关于表达式 sum [1,2,3] / len [1,2,3]:确实,像 1 这样的文字数字具有 类型数字a => a,它会在任何类型上调用 fromInteger,但像 1/2 这样的表达式具有更具体的 Fractional a 类型=> a,如果您询问该表达式的类型而不是打印出来,您就可以看到它。

ghci 中的 :set -Wall 可能会有所帮助,每当为您选择默认类型时,它都会打开大量警告,提示最通用的类​​型可能不再正确。

My avg function signature should have nothing to do with the division operator's quirks

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 of avg: Num doesn't have enough methods — basically enough to add, multiply, and subtract. There's no guarantee that the number I give to avg can be converted to a Double at all.

If you enter an untyped function to compute an average, Haskell responds with the most generic type possible:

Prelude List> :type \x -> sum x / genericLength x
\x -> sum x / genericLength x :: (Fractional a) => [a] -> a

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 to toRational or fromIntegral first, which use the Real and Integral instances for Integer, respectively.


Regarding the expression sum [1,2,3] / len [1,2,3]: It's true that a literal number like 1 has the type of Num a => a, which calls fromInteger on whatever type it turns out to be, but an expression like 1/2 has a more specific type of Fractional 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.

逆光下的微笑 2024-08-19 14:45:45

您过度限制 avg 的类型。使用更通用的版本, avg :: (Fractional a) => [一]->一个

You're overly constraining the type of avg. Use the more general version, avg :: (Fractional a) => [a] -> a

一笔一画续写前缘 2024-08-19 14:45:45

hhm 真正的问题是,如果它是整数类型,您想将其转换为小数类型,但如果它是小数类型,您想不理会它。

试试这个

fromRational ((sum xs) % (leng xs))

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

fromRational ((sum xs) % (leng xs))
终陌 2024-08-19 14:45:45

我遇到过这个问题。我所做的最好的事情是有两个求平均值的函数:一个用于积分,一个用于分数:

avgInt :: (Integral i, Fractional f) => [i] -> f
avgInt xs = fromIntegral (sum xs) / fromIntegral (length xs)

avgFrac :: (Fractional f) => [f] -> f
avgFrac xs = sum xs / fromIntegral (length xs)

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:

avgInt :: (Integral i, Fractional f) => [i] -> f
avgInt xs = fromIntegral (sum xs) / fromIntegral (length xs)

avgFrac :: (Fractional f) => [f] -> f
avgFrac xs = sum xs / fromIntegral (length xs)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文