我可以创建一个多态的`mult`函数,它可以采用任何数字类型吗?

时间:2017-03-16 02:08:39

标签: haskell types numbers polymorphism

我正在学习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

到目前为止我没有找到答案,但这似乎是一个简单的问题。我很感激能帮助我。

1 个答案:

答案 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实例。

详细了解类型类here,并记录Num的具体定义here,代码链接在页面一侧。 (没有足够的代表直接发布链接)