繁体   English   中英

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

[英]Why function (+) matches type (a -> b -> b)?

折叠功能:

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 for (+)函数?

由于折叠定义接受函数类型(a -> b -> b)这意味着前2个参数(a -> b)必须是不同类型的?

不,这意味着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

你在反方向思考。 您不必检查是否+相同或相匹配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 ((->) xx) ,它是类型构造函数->应用于x和类型构造函数->应用于xx 另一种类型是(->) a ((->) bb)

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

因此,我们必须统一xa 它们都是类型变量,因此我们可以重命名其中一个。 比方说,我们重命名a带有x 所以现在我们将重命名应用于类型,获得:( (->) x ((->) xx)(->) x ((->) bb) ,你会看到xx现在匹配。

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

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

关于类约束,当我们用b重命名x ,我们也将替换应用于约束,因此Num x变为Num b ,两个最终类型都是Num b => b -> b -> b

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


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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM