我正在学习Haskell。这是我写过的第一个程序,我只想创建一个返回给定参数的产品的简单函数。
mult :: a -> a -> a
mult x y = x * y
当我这样写的时候,我得到一个"推断类型"错误。
ERROR "uno.hs":5 - Inferred type is not general enough
*** Expression : mult
*** Expected type : a -> a -> a
*** Inferred type : Integer -> Integer -> Integer
它希望我这样写:
mult :: Int -> Int -> Int
mult x y = x * y
...这完全正常,但我想知道......这个功能也可以在Float
上运行吗?
它可以。
mult :: Float -> Float -> Float
mult x y = x * y
--then
mult 4 5 == 20.0
最后,我想知道:
我可以创建一个多态mult
函数,它可以采用任何数字类型吗?
为什么解析器会从同样适用于其他类型的函数中推断Integrer
?
到目前为止我没有找到答案,但这似乎是一个简单的问题。我很感激能帮助我。
答案 0 :(得分:3)
简短回答:mult :: Num a => a -> a -> a
并选择了Integer
,因为感觉这是一个不错的选择。
答案很长:
mult
不能是a -> a -> a
,因为这意味着它适用于每个类型a
,包括String,Char,Bool等。{ {1}}部分称为约束,它通过要求Num a =>
<的实例来限制a
的内容em>类型。这就像说“这个函数适用于任何类型,只要该类型具有此特定类型类的属性(具有实例)”。 Num
类型类的属性在标准库中定义,链接如下。
值得注意的是Num
本身的类型是(*)
,而且您的函数Num a => a -> a -> a
也可以定义为mult
。
它告诉您使用mult = (*)
的原因是因为Integer -> Integer -> Integer
的默认值是整数。你永远不应该依赖于这种情况,而应该写出完整的类型类约束类型签名。
当您指定类型签名Num
时,编译器会将该函数专门用于仅在Float -> Float -> Float
上工作,如您所料。这通过为Float
选择特定类型来解决a -> a -> a
引起的“过度承诺”问题,编译器知道该类型具有a
实例。