Ale*_*lan 3 haskell types casting
我想在Haskell中创建一个简单的平均(平均)函数,所以我在ghci中尝试了以下内容:
ghci> let avg xs = (sum xs) / (length xs)
Run Code Online (Sandbox Code Playgroud)
它会引发以下错误:
No instance for (Fractional Int)
arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Int)
In the expression: (sum xs) / (length xs)
In an equation for `avg': avg xs = (sum xs) / (length xs)
Run Code Online (Sandbox Code Playgroud)
因此,我决定通过尝试以下方法将其分解:
ghci> let a = (sum [1,2])
ghci> let b = (length [1,2])
Run Code Online (Sandbox Code Playgroud)
这一切都很好.
那么我尝试了以下内容
ghci> a/b
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Couldn't match expected type `Integer' with actual type `Int'
In the second argument of `(/)', namely `b'
In the expression: a / b
In an equation for `it': it = a / b
Run Code Online (Sandbox Code Playgroud)
那么,在Haskell中是Integer和Int不同的? - 如果是这样,我怎样才能使原始功能起作用?
ehi*_*ird 11
问题是
length :: [a] -> Int
Run Code Online (Sandbox Code Playgroud)
但
(/) :: (Fractional a) => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
所以,当你说whatever / length xs,它没有输入,因为Int不是分数数字类型!这就是"No instance for ..."错误试图告诉你的.这个定义可行:
GHCi> let avg xs = sum xs / fromIntegral (length xs)
Run Code Online (Sandbox Code Playgroud)
在这里,我们使用fromIntegral :: (Integral a, Num b) => a -> b将我们得到的Int length转换为分数.请注意,由此产生的函数仅适用于小数的列表(但avg [1,2,3]仍然可以正常工作).
为了解释你在"分片"中所做的错误,这是因为在let a = sum [1,2],列表的元素是整数,所以它们的和是一个整数,但是let b = length [1,2],根据length上面显示的类型,得到的长度是一个Int .所以,当你这样做时a/b,在它甚至意识到Int和Integer不是Fractional的实例之前就失败了 - 因为(/)它接受了两个相同类型的参数,它不可能工作.
是的,Integer和Int是不同的 - Int是一个固定精度的整数类型,通常是数字的大小,就像long在C中一样,而Integer是一个任意精度的bignum,能够存储任何整数; 或者至少,任何适合你的RAM的整数:)
另一种可能的方法是定义avg xs为sum xs / genericLength xs,使用Data.List.genericLength哪个适用于任何数字类型,而不仅仅是Ints:
genericLength :: (Num b) => [a] -> b
Run Code Online (Sandbox Code Playgroud)
为此,你必须import Data.List在GHCi.另一种可能的方法(但是一种导致完全不同的功能)将是使用整数除法:( let avg xs = sum xs `div` length xs注意:a `div` b只是div a b;这种语法糖适用于每个函数).