Haskell中的Length函数和类型类

时间:2014-06-02 03:27:39

标签: list haskell

media :: (Num a) => [a] -> a
media [] = 0
media lst = (head lst) + media (tail lst)

这是一个工作函数,它遍历一个数字列表,并使用以下元素对每个元素求和。

media2 :: (Num a) => [a] -> a
media2 str = (media str) / (length str)

第二个函数应该得到该总和并将其除以列表的长度,从而获得列表的算术平均值。但编译器会将此返回

src/Main.hs@6:29-6:39Could not deduce (a ~ Int)
from the context (Num a)
bound by the type signature for media2 :: Num a => [a] -> a
at /home/app/isolation-runner-work/projects/32614/src.207/Main.hs:6:1-39
`a' is a rigid type variable bound by
the type signature for media2 :: Num a => [a] -> a
at /home/app/isolation-runner-work/projects/32614/src.207/Main.hs:6:1
In the return type of a call of `length'
In the second argument of `(/)', namely `(length str)'
In the expression: (media str) / (length str)

我不明白我做错了什么,有人可以告诉我吗?

2 个答案:

答案 0 :(得分:4)

length函数始终返回Int,因此您尝试将(Num a) => a除以IntfromIntegral函数会将Int转换为任何Num类型:

media2 :: (Fractional a) => [a] -> a
media2 str = (media str) / (fromIntegral $ length str)

修改

关于一些富有洞察力的评论只是几句话:

  1. 您的media功能只是Prelude的sum
  2. 我假设您并不总是想要Integral平均值,因此我已将media2上的约束更改为Fractional而不是Num }。这是因为/的类型为(/) :: (Fractional a) => a -> a -> a。或者,您可以使用

    media2 :: (Integral a) => [a] -> a
    media2 str = (media str) `div` (fromIntegral $ length str)
    

    但你总会得到一个整数平均值,这可能不是你想要的。

答案 1 :(得分:2)

您可以使用Data.List中的genericLength

  

genericLength函数是length的重载版本。特别是,它不返回Int,而是返回任何Num实例的类型。然而,它的效率低于长度。

它的类型签名是

genericLength :: Num i => [a] -> i 

用法:

import Data.List

media2 :: (Num a) => [a] -> a
media2 str = (media str) / (genericLength str)