我正在编写一个计算标准偏差的函数。
代码:
stdDev :: [float]->float
stdDev [] = 0.0
stdDev list = sqrt (foldl (\x-> fromIntegral(x^2/length list)) 0 list - foldl (\x->fromIntegral(x/length list)^2) 0 list)
编译时,显示:
Couldn't match type `float' with `Int'
我已经使用fromIntegral投了它。我不明白为什么它还在抱怨它。
答案 0 :(得分:3)
首先,类型必须以大写字母开头。如果不是,则将它们解释为类型变量
stdDev :: [Float] -> Float
stdDev [] = 0.0
接下来,您不需要那里的所有fromIntegral
,您不使用Integral
类型。如果我们使用where子句来计算长度,我们也会得到一个更有效的函数。不幸的是,你没有正确使用foldl
,它需要两个参数的函数,你只需要传递一个函数1.你的标准偏差函数也有点偏,看起来应该是
stdDev xs = sqrt $ (sum $ map (^2) xs) / l - (sum xs / l) ^ 2
where l = fromIntegral $ length xs
作为最后的改进,您可以通过使用类型类1>来为实现Floating
的任何类型(包括Float
和Double
)使其工作
stdDev :: Floating a => [a] -> a
stdDev [] = 0
stdDev xs = sqrt $ (sum $ map (^2) xs) / l - (sum xs / l) ^ 2
where l = fromIntegral $ length xs
所以我们可以测试一下:
> stdDev [1, 1, 1]
0.0
> stdDev [2, 4, 4, 4, 5, 5, 7, 9]
2.0
所以看起来它正在运作
如果你真的想要使用折叠,你必须传递一个带有两个参数的函数。要使用的一般模式是
foldl (\acc x -> <expr>) <initial value> <list>
总和来说,它就像
一样简单foldl (\acc x -> acc + x) 0 xs
但出于性能原因,你应该在这里使用foldr
,它可以简化为
foldr (+) 0 xs
在你的情况下,你需要一个简单的总和,然后是一个平方和,所以你可以做
mySum xs = foldr (+) 0 xs
sumSqrs xs = foldr (\acc x -> acc + x ^ 2) 0 xs
因此,您可以在stdDev
中使用这些作为
stdDev xs = sqrt $ foldr (\acc x -> acc + x ^ 2) 0 xs / l - (foldr (+) 0 xs / l) ^ 2
where l = fromIntegral $ length xs
答案 1 :(得分:0)
float
应该大写:Float
。类型签名中以小写字母开头的任何内容都是Haskell中的类型变量。
此外,传递给foldl
的函数必须带两个参数。在这种情况下,我认为您希望map
列表中的函数,然后将所有结果项与sum
相加,而不是foldl
(对于标准偏差的天真实现)。
您可能还希望从genericLength
查看Data.List
,该Num
评估的值可以用作Float
类型类的任何实例(包括{{1}})