此Lambda函数返回1:
(x y -> 1) 1 p
其中p=(\xy->1)
好吧,这对我来说很有意义——Lambda函数返回1,与它的参数无关。
现在,这个Lambda函数生成一个错误(无限类型错误):
(x y -> x y x) p 1
这对我来说没有意义。如果这个函数应用于这里的参数,则是用p代替x,用1代替y的结果:
p 1 p
用其定义替换第一个p:
(x y -> 1) 1 p
嘿!这与上面的相同,返回1。
问题:为什么(\xy->1)1 p成功,而(\xy->x y-x)p 1失败?
/收到
使用以下表达式(其中两个p
必须具有相同的类型,因为如果不显式指定多态类型,lambda变量就不能同时具有两个类型):
p 1 p
在这种情况下,p
的类型是什么?为了简单起见,假设1
是Int
。让我们从一个简单的尝试开始:
(p :: Int -> ? -> Int) 1 p
那么,问号是什么呢?它必须是p
的类型,因为这就是你给出的论点。因此:
(p :: Int -> (Int -> ? -> Int) -> Int) 1 p
同样的问题,同样的解决方案:
(p :: Int -> (Int -> (Int -> ? -> Int) -> Int) -> Int) 1 p
现在你明白了为什么我们有无限类型的问题:虽然我们不需要来知道p
的第二个参数的类型;因为Haskell类型系统是严格的(又称不懒惰),所以它无论如何都需要找出类型,并被这种无限类型所困扰。
此代码成功:
(x y -> 1) 1 p
因为左边的函数可以具有与p
不同的类型,因为它们是不同的函数,所以我们在尝试统一类型时不会遇到相同的问题:
(( x y -> 1) :: a -> b -> Int) 1 (p :: c -> d -> Int)
除了dflemstr所说的,lamba的类型永远不会取决于它所应用的值。类型检查器将首先找到lambda的类型,然后检查它是否正确应用。
因此,您认为在beta替换后表达式是相同的论点是无关紧要的:lambda必须是孤立的良好类型。