Racket 小打字机。我不知道';我不理解λ的最初第二条戒律的含义;
我试过下面的例子,但不管y发生与否, 函数f在应用后返回与(λ(y)(fy))相同的值 我想做的是定义一个函数,当Y作为反例出现在Y中时,它与(λ(Y)(fy))不同(->yx),但我不知道如何定义 我是否误解了λ的最初第二条戒律的含义Racket 小打字机。我不知道';我不理解λ的最初第二条戒律的含义;,racket,lambda-calculus,type-theory,pie-lang,Racket,Lambda Calculus,Type Theory,Pie Lang,我试过下面的例子,但不管y发生与否, 函数f在应用后返回与(λ(y)(fy))相同的值 我想做的是定义一个函数,当Y作为反例出现在Y中时,它与(λ(Y)(fy))不同(->yx),但我不知道如何定义 我是否误解了λ的最初第二条戒律的含义 ;;y does not occurs (claim f (-> Nat Nat)) (define f (λ(y) 0)) ;; both return (the Nat 0) (f 5) ((the (-> Nat Nat)
;;y does not occurs
(claim f (-> Nat Nat))
(define f
(λ(y)
0))
;; both return (the Nat 0)
(f 5)
((the (-> Nat Nat)
(λ(y)
(f y)))
5)
;; y occurs
(claim g (-> Nat Nat))
(define g
(λ(y)
y))
;;both return (the Nat 5)
(g 5)
((the (-> Nat Nat)
(λ(y)
(g y)))
5)
为了创建一个示例来说明警告的重要性“…只要
y
不出现在f
”中,我们需要创建一个函数f
,其中的名称y
是自由出现的。关于y
在f
中免费的规定至关重要。这也是为什么很难创建这样一个示例的原因:(顶级)函数不能包含自由变量。但是,其他函数内部的函数可以。这是关键
下面是函数g
,其中包含另一个函数:
(claim g (-> Nat
(-> Nat
Nat)))
(define g
(lambda (y)
(lambda (x) ;; Call this inner
y))) ;; function "f"
(我选择这样写声明是为了强调我们在考虑函数内部的函数。)
为了确定方向,这个简单的函数g
需要两个Nat
参数,并返回第一个参数
让我们调用内部函数f
。请注意,f
包含一个自由变量y
(因此,f
在g
之外没有意义)。让我们用(lambda(y)(fy))替换f
:
(claim g1 (-> Nat
(-> Nat
Nat)))
(define g1
(lambda (y)
(lambda (y) ;; Here we've replaced "f"
((lambda (x) ;; with an eta-expanded
y) ;; version, introducing
y)))) ;; the name "y"
我们可以删除应用程序以生成以下表达式:
g1
---------------- SAME AS
(lambda (y)
(lambda (y)
((lambda (x)
y)
y)))
---------------- SAME AS
(lambda (y)
(lambda (y)
y))
---------------- SAME AS
(lambda (y)
(lambda (y1)
y1))
在最后一步中,我将第二个y
重命名为y1
,以说明内部函数体中的变量指的是较近的绑定位点,而不是较远的绑定位点
总而言之,我们从一个函数g
开始,该函数“接受两个(curried)参数并返回第一个”。然后,我们在内部函数周围引入了错误的eta扩展。结果,我们得到了一个函数g1
,它“接受两个(curried)参数并返回第二个”。显然不等同于原始函数g
所以这条戒律是关于变量捕获的,这是我们为使用名称而付出的代价。我希望这有帮助
重要提示:
由于饼图检查类型的方式,如果要尝试此示例,则需要在g
的主体中引入注释:
(claim g1 (-> Nat
(-> Nat
Nat)))
(define g1
(lambda (y)
(lambda (y)
((the (-> Nat Nat)
(lambda (x)
y))
y))))
我不确定我是否理解正确,或者这是否有任何帮助,但请注意,(λ(y)(fy))
实际上等同于f
,因为当你应用((λ(y)(fy))5
,你会得到(f5)
,这与将f
应用于5是一样的。