我有两个功能
(\f b -> (\a -> a) f b b)
和
(\f b -> (\a -> 0) f b b)
我试着用手找出这些函数的类型
(t1 -> t1 -> t2) -> t1 -> t2
和
Num t3 => (t1 -> t1 -> t2) -> t1 -> t3
但是,当我使用GHCI使用:t
获取类型时,我得到以下信息
(\f b -> (\a -> a) f b b) :: (t1 -> t1 -> t2) -> t1 -> t2
(\f b -> (\a -> 0) f b b) :: Num (t1 -> t1 -> t2) => p -> t1 -> t2
我不明白如何将\a -> a
更改为\a -> 0
将第一个参数从(t1 -> t1 -> t2)
更改为p
发布于 2018-07-29 04:19:47
导出(\f b -> (\a -> a) f b b)
的类型
那么,让我们尝试导出表达式的类型:
(\f b -> (\a -> a) f b b)
或者更详细:
(\f -> (\b -> (((\a -> a) f) b) b))
我们在这里看到,这是一个接受两个参数的函数(从技术上讲,函数总是有一个参数,这个函数的结果可以是另一个参数,但是假设如果我们讨论“两个参数”,我们指的是这样的结构)。
因此,参数是f
和b
,最初我们对这些参数不太了解,因此我们为它们分配了一个类型,表达式如下:
f :: g
b :: h
(\f b -> (\a -> a) f b b) :: g -> (h -> i)
因此,我们创建了三种类型的g
、h
和i
(这里我使用了a
、b
和c
以外的其他标识符,因为这可能导致与变量混淆)。
但是我们还没有完成,因为表达式本身可以对类型的行为带来更多的限制。例如,我们看到一个lambda表达式:\a -> a
,它显然具有类型:
\a -> a :: j -> j
接下来,我们看到一个函数应用程序,函数是\a -> a
,参数是f
,这意味着g ~ j
(g
和j
是相同的类型),(\a -> a) f
的类型是(\a -> a) f :: g
。
但是我们还没有完成,因为(\a -> a) f
的结果现在在b
的函数应用程序中充当一个函数,因此这意味着g
实际上是一个函数,具有输入类型h
和一些(当前未知的输出类型),因此:
g ~ (h -> k)
所以(\a -> a) f b
的类型是k
,但是我们还没有完成,因为我们执行另一个函数应用程序,(\a -> a) f b
作为函数(类型k
),b
作为参数,这意味着k
实际上是一个函数,h
是参数类型,结果是表达式的类型,所以i
。这意味着我们有:
g ~ j
g ~ (h -> k)
k ~ (h -> i)
换句话说,表达式的类型是:
(\f b -> (\a -> a) f b b) :: (h -> (h -> i)) -> (h -> i)
或者不那么冗长:
(\f b -> (\a -> a) f b b) :: (h -> h -> i) -> h -> i
导出(\f b -> (\a -> 0) f b b)
的类型
派生的第一步大致相同,我们首先引入一些类型变量:
f :: g
b :: h
(\f b -> (\a -> 0) f b b) :: g -> (h -> i)
现在我们开始做推论。我们首先推断出(\a -> 0)
的类型。这是一个函数,类型为Num l => j -> l
,因为0
是Num
ber,但它可以是任何Num
类型,并且与参数a
的类型无关。
接下来,我们看到有一个函数调用,函数以(\a -> 0)
为函数,f
为参数,因此我们得出了g ~ j
的结论。此函数调用的结果类型为(\a -> 0) f :: Num l => l
。
现在我们看到了另一个函数调用,函数是(\a -> 0) f
,参数是b
。因此,我们得出结论,l
是一个函数(所以是l ~ (h -> k)
)。
最后一个函数调用是以(\a -> 0) f b :: k
作为函数,b
再次作为参数。这意味着k
是一个函数k ~ h -> i
。因此,我们得到了以下类型和等式:
f :: g
b :: h
(\a -> 0) :: Num l => j -> l
(\f b -> (\a -> 0) f b b) :: g -> (h -> i)
g ~ j
l ~ (h -> k)
k ~ (h -> i)
因此,表达式的类型如下:
(\f b -> (\a -> 0) f b b) :: g -> (h -> i)
或者更具体地说:
(\f b -> (\a -> 0) f b b) :: Num (h -> (h -> i)) => g -> (h -> i)
或者不那么冗长:
(\f b -> (\a -> 0) f b b) :: Num (h -> h -> i) => g -> h -> i
因此,既然我们使用(\a -> 0)
作为内部lambda表达式,那么f
的类型和值就不再相关了。(\a -> 0) f
将始终返回0
,这应该是一个可以考虑b
的函数。
至少从理论上看,作为Num
的函数没有什么“奇怪”(只要它支持应该由Num
类型实现的函数)。例如,我们可以实现一个函数instance Num (a -> b -> Int)
,从而将0
看作总是映射到0
的常量函数,而(+)
则是构造将这两个函数相加在一起的新函数的一种方法。
https://stackoverflow.com/questions/51580107
复制