Haskell中推断的函数类型

时间:2016-11-24 09:01:03

标签: haskell

我在Haskell中定义了一个函数

func x | x > 0 = 4
       | otherwise = error "Non positive number"

其推断类型是

func :: (Ord a, Num a, Num t) => a -> t

为什么它的类型不能

func :: (Ord a, Num a) => a -> a

3 个答案:

答案 0 :(得分:6)

类型func :: (Ord a, Num a) => a -> a表示返回的类型应该与您传入的类型匹配。但是由于您返回的是常量并且它不依赖于输入,因此其类型可以是任何类型的类{{1} }。因此,编译器会推断Num

答案 1 :(得分:4)

推断类型是正确的。让我们看看它是如何被推断出来的。我们只会先查看返回值:

func x | … = 4
       | … = error "…"

后一个词error "…" :: a不受约束。但是,4的类型为Num a => a,因此您的函数将具有类型

func :: (Num result) => ????? -> result

现在让我们看看x

func x | x > 0 = …
       | …   

由于使用了(>) :: Ord a => a -> a- > Bool0 :: Num ax必须是NumOrd的实例。所以从这个角度来看,我们已经

func :: (Num a, Ord a) => a -> ????

重要的是,4x不会互动。因此func

func :: (Num a, Ord a, Num result) => a -> result

当然,resulta可以是同一类型。顺便说一下,只要您连接x4,类型就会更具体:

func x | x > 0 = 4 + x - x
       | …

将具有(Num a, Ord a) => a -> a类型。

答案 2 :(得分:2)

您可能或可能不知道,Haskell’s numeric literals are polymorphic。这意味着,04等数字文字的类型为Num a => a。您似乎已经理解了这一点,因为您期望的类型签名包含Num约束。

事实上,您提供的类型签名是有效签名。如果你包含它,它将被编译器接受,如果它是你真正想要的类型,通过包括它。但是,它与推断类型的不同之处在于Haskell将尝试推断最通用的类型,并且推断类型比您编写的类型更通用。

问题是,为什么允许推断类型?好吧,考虑一下这个相似但不同的功能:

func' x | x > 0 = "ok"
        | otherwise = error "Non positive number"

此函数的类型为(Ord a, Num a) => a -> String。值得注意的是,除了结果是否为⊥之外,函数的输入对输出完全没有影响。出于这个原因,结果可以是任何东西,包括字符串。

然而,考虑另一个功能,再次类似但不同:

func'' x | x > 0 = x - 1
         | otherwise = error "Non positive number"

此函数必须具有您描述的类型,因为它使用x来生成新值。

但是,请再次查看原始func定义。请注意右侧的文​​字4x没有任何关系。该定义实际上比func'更接近func'',因此数字文字具有Num t => t类型,并且它永远不需要专门化。因此,推断类型允许两个数字类型分开,并且您在问题中编写了更通用的类型。