我对派生类型有一个真正的问题,根本不了解,如何派生类型。
我使用以下实现定义了一个函数f
:
f x y z = x * y * z
函数f
的类型签名是:
f :: Num c => c -> c -> c -> c
很简单,对吧?
现在,将f
应用于map
和id
功能并查看类型签名。
首先,让我们应用map f
:
a -> b "The signature of the first argument of map
~ ~
c -> c -> c -> c "The signature of the f function
您可以在上面看到,我如何分离并获得类型相等,即a ~ c
和b ~ c -> c -> c
。
然后,让我们应用id f
a -> a "The signature of the id
~ ~
c -> c -> c -> c "The signature of the f function
就像我上面分开的那样,我会说a ~ c
和a ~ c -> c -> c
,但这是错误的,我不明白为什么。我完全像上面那样做了原理。权利是a ~ c -> c -> c -> c
。
有人可以一步一步地向我解释一下,派生类型如何运作?我会说,我完全理解派生类型的概念。
答案 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 ~ c
和b ~ 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 -> c
是c -> (c -> (c -> c))
的缩写。所以我们有一个函数(带有一个参数),它返回一个函数c -> (c -> c)
。
答案 2 :(得分:4)
您的第一个示例绝对正确,当您有map f
时,您应该将map
(a -> b
)的第一个参数的类型与{{1}的类型相匹配}(f
),然后你的结论是正确的:
c -> c -> c -> c
要找到a ~ c
b ~ c -> c -> c
的类型,我们应该删除map f
的第一个参数,因为它已经绑定到map
,并根据上面的结论继续进行替换:
f
但是,您没有正确匹配第二个示例中的类型。如果您有[a] -> [b] ~ [c] -> [c -> c -> c]
,则应再次将id f
(id
)的第一个参数的类型与a
(f
)的类型相匹配。我们可以从中得出结论:
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
,并且具有相同的类型。