为什么函数(+)匹配类型(a - > b - > b)?

时间:2015-05-27 09:54:57

标签: haskell

折叠功能:

fold :: b -> (a -> b -> b) -> [a] -> b
fold z f []     = z
fold z f (x:xs) = f x (fold z f xs)

取自http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html

Prelude> :t (+)
(+) :: Num a => a -> a -> a

*Main> fold (0) (+) [1,2,3]
6

类型(a -> b -> b)a -> a -> a函数的类型(+)匹配是什么?

由于折叠定义接受函数类型(a -> b -> b),这意味着前2个参数(a -> b)需要具有不同类型?

2 个答案:

答案 0 :(得分:15)

不,这意味着ab 可能会有所不同,但并非强制要求它不同。在你的情况下,它是相同的。

一个更简单的例子来传达这一点:

data SomeType a b = Test a b deriving (Show)

现在在ghci

λ> :t Test
Test :: a -> b -> SomeType a b
λ> let x = Test (3 :: Int) (4 :: Int)
λ> :t x
x :: SomeType Int Int

答案 1 :(得分:3)

你在反方向思考。您无需检查+是否相同或匹配a -> b -> b,您希望+的类型为a -> b -> b专业化和要检查这一点,你必须统一类型。

统一意味着您希望通过重命名类型变量来查看+的类型和a -> b -> b类型是否相等。

因此+的类型为Num x => x -> x -> x。让我们暂时忽略类约束,让我们看看我们是否可以匹配函数类型。 类型变为x -> x -> xa -> b -> b。事实上,如果我们按原样查看它们会更好,而不使用关联性:x -> (x -> x)a -> (b -> b)

->类型构造函数。即它是将一定数量的类型映射到不同类型的函数。在这种情况下,->构造函数会将两种类型t_1t_2映射到函数类型(->) t_1 t_2(通常用t_1 -> t_2表示)。

因此类型x -> (x -> x)实际上是(->) x ((->) x x),它是应用于->的类型构造函数x以及应用于{{1的类型构造函数-> }和x。 另一种类型是x

统一时,考虑两种类型的最外层类型构造函数(在这种情况下,两者都是(->) a ((->) b b))。如果这不匹配,则无法统一。 否则你必须统一构造函数的参数。

因此,我们必须将->x统一起来。它们都是类型变量,因此我们可以重命名其中一个。假设我们使用a重命名a。现在我们将重命名应用于类型,获取:x(->) x ((->) x x),您会看到(->) x ((->) b b)x现在匹配。

让我们考虑第二个论点。它不是一个类型变量,所以我们必须匹配类型构造函数,这两者都是x。所以我们以递归方式处理论证。

我们希望匹配->x。它们都是类型变量,因此我们可以重命名其中一个。假设我们将b重命名为x。我们将此替换应用于类型,获取:b(->) b ((->) b b)。现在一切都匹配。因此这两种类型统一起来。

关于类约束,当我们使用(->) b ((->) b b)重命名x时,我们也将替换应用于约束,因此b变为Num x,两个最终类型都是{ {1}}。

我希望这能让您更好地了解类型的工作方式以及如何检查类型。

旁注:这是haskell在执行类型推断时所做的事情。它首先为未知函数分配一个新的类型变量Num b。然后它使用统一来获取定义它的表达式的类型,并检查与Num b => b -> b -> b关联的类型,这是函数的类型。