函数签名中的类型变量

时间:2018-07-31 01:42:27

标签: haskell

如果我执行以下操作

functionS (x,y) = y
:t functionS
functionS :: (a, b) -> b

现在具有此功能:

functionC x y = if (x > y) then True else False
:t function

我希望得到:

functionC :: (Ord a, Ord b) => a -> b -> Bool

但是我得到了

functionC :: Ord a => a -> a -> Bool

GHCI似乎可以接受之前的2个结果,但是为什么给我第二个结果呢?为什么未定义类型变量a和b?

1 个答案:

答案 0 :(得分:3)

我认为您可能会误读类型签名。毫无疑问,您用来指导思想的示例令人困惑。特别是在您的元组示例中

functionS :: (a,b) -> b
functionS (x,y) = y

符号(_,_)表示两种不同的含义。在第一行中,(a,b)指的是 type ,其对的类型为第一个元素的类型为a,第二个元素的类型为b。在第二行中,(x,y)指的是特定的一对,其中x的类型为a,而y的类型为b。尽管此“双关语”提供了有用的助记符,但在您初次使用它时可能会造成混淆。我希望对的类型是常规类型的构造函数:

functionS :: Pair a b -> b
functionS (x,y) = y

因此,继续您的问题。在签名中,您会得到

functionC :: Ord a => a -> a -> Bool

a类型Ord a说类型a的元素相对于彼此是可排序的。该函数接受两个 same 类型的参数。可排序的某些类型是Integer(按数字),String(按字典顺序),以及其他一些。这意味着您可以知道两个Integer中哪个较小,或者两个String中哪个较小。但是,我们不一定知道如何判断Integer是否比String小(这很好!您见过哪种shenanigans了吗? javascript必须支持无类型的相等性吗?Haskell根本不需要解决这个问题!)。这就是这个签名的意思-只有一个单一的可排序类型a,并且该函数接受了同一类型的两个元素。

您可能仍然想知道为什么functionS的签名具有两个不同的类型变量。这是因为没有约束将它们限制为相同,例如必须将它们彼此相对排序。 functionS在一对组成部分都为整数的对上同样有效,就像一个是整数而另一个是字符串一样。没关系Haskell总是选择最有效的最普通类型。因此,如果不强迫它们相同,则它们将不同。

有更多的技术方法可以解释所有这些,但是我觉得应该有一个直观的解释。希望对您有所帮助!