逐步推导类型

时间:2017-08-07 14:19:02

标签: haskell

我对派生类型有一个真正的问题,根本不了解,如何派生类型。

我使用以下实现定义了一个函数f

f x y z = x * y * z

函数f的类型签名是:

f :: Num c => c -> c -> c -> c
很简单,对吧?

现在,将f应用于mapid功能并查看类型签名。

首先,让我们应用map f

a -> b "The signature of the first argument of map
~    ~
c -> c -> c -> c "The signature of the f function

您可以在上面看到,我如何分离并获得类型相等,即a ~ cb ~ c -> c -> c

然后,让我们应用id f

a -> a           "The signature of the id
~    ~
c -> c -> c -> c "The signature of the f function

就像我上面分开的那样,我会说a ~ ca ~ c -> c -> c,但这是错误的,我不明白为什么。我完全像上面那样做了原理。权利是a ~ c -> c -> c -> c

有人可以一步一步地向我解释一下,派生类型如何运作?我会说,我完全理解派生类型的概念。

4 个答案:

答案 0 :(得分:7)

你实际上是在问题中自己写的:

  • a -> b -- The signature of the first argument of map
  • a -> a -- The signature of id

要比较苹果和苹果,您需要从

开始
  • a -> b -- The signature of the first argument of map
  • a -- The signature of the first argument of id

答案 1 :(得分:4)

你的第二次尝试不起作用。在您的问题中,您说(粗体添加):

  

首先,让我们应用map f

a -> b "The signature of the first argument of map
~    ~
c -> c -> c -> c "The signature of the f function
     

您可以在上面看到,我如何分离并获得类型相等,即a ~ cb ~ c -> c -> c

     

然后,让我们应用id f

a -> a           "The signature of the id
~    ~
c -> c -> c -> c "The signature of the f function

因此,对于您正确推理的第一个案例map f,请使用map第一个参数的类型。但是,在后一种情况下,您使用 整个签名 。你应该再次使用第一个参数。

所以让我们纠正一下:

a                "The first argument of the id
~
c -> c -> c -> c "The signature of the f function

这意味着a ~ c -> c -> c -> c。因此,id f具有签名c -> c -> c -> c

请注意,在Haskell中每个函数只有一个参数c -> c -> c -> cc -> (c -> (c -> c))的缩写。所以我们有一个函数(带有一个参数),它返回一个函数c -> (c -> c)

答案 2 :(得分:4)

您的第一个示例绝对正确,当您有map f时,您应该将mapa -> b)的第一个参数的类型与{{1}的类型相匹配}(f),然后你的结论是正确的:

c -> c -> c -> c

要找到a ~ c b ~ c -> c -> c 的类型,我们应该删除map f的第一个参数,因为它已经绑定到map,并根据上面的结论继续进行替换:

f

但是,您没有正确匹配第二个示例中的类型。如果您有[a] -> [b] ~ [c] -> [c -> c -> c] ,则应再次将id fid)的第一个参数的类型与af)的类型相匹配。我们可以从中得出结论:

c -> c -> c -> c

然后删除a ~ c -> c -> c -> c 的第一个参数,我们只剩下id,我们可以进行简单的替换以获得a的类型:

id f

答案 3 :(得分:2)

map的类型为(a -> b) -> [a] -> [b],因此map f的类型为Num a => [a] -> [a -> a -> a]。为什么呢?

map的第一个参数是函数a -> b,因此您可以将f的第一个参数替换为a。由于f的类型为Num a => a -> a -> a -> a,因此当您使用'它的第一个参数,返回类型是一个函数 Num a => a -> a -> a。它是部分应用的功能。函数与单个值不同,但它仍然有一个类型,您可以调用b

同样,id的类型为a -> a,这意味着它只返回与输入相同的值。如果输入为f,则输出也为f,并且具有相同的类型。