【问题标题】:Haskell dividing numHaskell 除数
【发布时间】:2010-12-21 11:31:12
【问题描述】:

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

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: 无法将预期类型“Double”与推断类型“t”匹配 `t' 是一个刚性类型变量,由 len.hs:5:12 处“avg”的类型签名 在表达式中:(sum xs) / (len xs) 在 `avg' 的定义中:avg xs = (sum xs) / (len xs)

现在,我知道这个错误(感谢 irc.freenode.net#haskell)是除法函数的结果

(/) :: (Fractional a) => a -> a -> a

但是,我不知道该怎么做。我的avg 函数签名应该与除法运算符的怪癖无关(需要Fractional 类型类)。所以,我认为克服这个问题的正确方法是通过强制转换为暗示他们Fractional typeclass 的类型,但我不知道如何,或者即使这是正确的?有什么想法吗?

【问题讨论】:

    标签: haskell types division typeclass


    【解决方案1】:

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

    试试这个

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

    【讨论】:

    • mauke in irc 17:14 < mauke> EvanCarroll: % requires integers 和他说话太难了。我不想问他这是什么意思。 :t (%) 也没有显示任何有用的信息。
    • @Evan: upshaw 的代码使用haskell.org/ghc/docs/latest/html/libraries/base/Data-Ratio.html -- 只有当列表元素是整数时才有效。
    【解决方案2】:

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

    【讨论】:

    • 我的问题是,为什么len 返回的东西是Fractional 类型类成员的一部分,:t sum [1,2,3]:t len [1,2,3] 都显示结果只是一部分Num 类型类。我很困惑如何在此处应用一个要求其参数与 Fractional 类型类分开的函数。
    • EvanCarroll:Num 类型类不提供小数除法,但 Fractional 类型类提供。由于avg 在其顶级计算中使用/,因此类型签名必须反映这一点。当您进行此更改时,编译器知道在 sumlen 中使用浮点数学。
    【解决方案3】:

    我的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 来解决此问题,它们分别使用IntegerRealIntegral 实例。


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

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

    【讨论】:

    • 我选择了这个作为答案,(肯定付出了最大的努力)但我想快速跟进一个资源,我可以在其中找到前奏对类型和类型的内容-关于类数类型的类。通过要求输入与分数分开,我排除了哪些类型的整数?在执行 `:t (/) 之前,我从未见过除此类型类之外的类型,我想更多地了解它是如何工作的。而且,事情神奇地加入了师的班级
    • 所有这些声明都在前奏曲中。在线参考:haskell.org/ghc/docs/6.10.2/html/libraries/base/Prelude.html
    • 我曾经看到一个有向无环图显示数字类型类层次结构,但现在找不到了。这里有一个温和的介绍:(haskell.org/tutorial/numbers.html)。您可以使用:i (/) 或 :i 在类型或类上告诉 ghci 为您提供更多信息。
    【解决方案4】:

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

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-31
      • 2016-04-16
      • 2012-08-30
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 2015-06-25
      相关资源
      最近更新 更多