如何理解Haskell中的嵌套lambda函数

如何理解Haskell中的嵌套lambda函数,haskell,functional-programming,Haskell,Functional Programming,我试图理解Haskell中以下两个lambda表达式的含义: f = \x -> x (\y -> x y) g = \x -> (\y -> y) x 我试着改变他们,我得到了这个: f x y = x x y g x y = y x 这是正确的吗?我假设这两个函数的参数都必须是x和y,因为它们都可以在函数描述中的lambda表达式中找到。我基本上是这样理解的:fx=xfy和fy=yx。对于g,gx=gyx和gy=y。但由于我是哈斯克尔的新手,我对这些类型的转换不是

我试图理解Haskell中以下两个lambda表达式的含义:

f = \x -> x (\y -> x y)
g = \x -> (\y -> y) x
我试着改变他们,我得到了这个:

f x y = x x y
g x y = y x

这是正确的吗?我假设这两个函数的参数都必须是x和y,因为它们都可以在函数描述中的lambda表达式中找到。我基本上是这样理解的:fx=xfy和fy=yx。对于g,gx=gyx和gy=y。但由于我是哈斯克尔的新手,我对这些类型的转换不是很有信心。如果不正确,什么是正确的转换?

两者都不正确。您的解决方案使用这些函数

f x y = x x y
g x y = y x
这实际上意味着

f = \x -> (\y -> x x y)
g = \x -> (\y -> y x)
这些与最初的表达不同

f = \x -> x (\y -> x y)
g = \x -> (\y -> y) x
上述两个方程可以改写为

f x = x (\y -> x y)
g x = (\y -> y) x
但是从这里开始,没有办法将剩余的lambda转换为f或g的更多参数。充其量,我们可以使用beta/eta转换简化它们,并获得

f x = x x            -- eta  (\y -> x y) = x
g x = x              -- beta (\y -> y) x = x
另请参见威尔·内斯(Will Ness)的评论,他指出,通过在f中的额外eta扩展,我们可以达到OP的定义。不过,这是偶然的


最后,请注意,Haskell不会接受fx=xx,因为它不能被类型化,除非我们使用rank-2类型并显式地提供像f::forall a这样的类型注释。a->b。原始代码f=\x->x\y->x y也有同样的问题。这在非类型化语言中也可以,例如编程语言理论中的非类型lambda演算。

两者都不正确。您的解决方案使用这些函数

f x y = x x y
g x y = y x
这实际上意味着

f = \x -> (\y -> x x y)
g = \x -> (\y -> y x)
这些与最初的表达不同

f = \x -> x (\y -> x y)
g = \x -> (\y -> y) x
上述两个方程可以改写为

f x = x (\y -> x y)
g x = (\y -> y) x
但是从这里开始,没有办法将剩余的lambda转换为f或g的更多参数。充其量,我们可以使用beta/eta转换简化它们,并获得

f x = x x            -- eta  (\y -> x y) = x
g x = x              -- beta (\y -> y) x = x
另请参见威尔·内斯(Will Ness)的评论,他指出,通过在f中的额外eta扩展,我们可以达到OP的定义。不过,这是偶然的

最后,请注意,Haskell不会接受fx=xx,因为它不能被类型化,除非我们使用rank-2类型并显式地提供像f::forall a这样的类型注释。a->b。原始代码f=\x->x\y->x y也有同样的问题。这在非类型化语言中也可以,例如编程语言理论中的非类型lambda演算。

GHCi提示符下的:type命令是您的朋友。让我们先举第二个例子

λ> :type let g = \x -> (\y -> y) x in g
let g = \x -> (\y -> y) x in g :: p -> p
因此,g是类型良好的,并且是编写标识函数::p->p的复杂方式。具体地说,g获取一些x并将标识函数\y->y应用于x,从而得到x。GHCi在给出类型时使用了一个新的类型名p,以避免混淆。不,你的Gxy=。。。这是不等价的。用:type检查它

您可以将:type缩写为:t。那么让我们来举你的第一个例子

λ> :t let f = \x -> x (\y -> x y) in f
* Occurs check: cannot construct the infinite type: t2 ~ t2 -> t3
* In the first argument of `x', namely `(\ y -> x y)'
  In the expression: x (\ y -> x y)
  In the expression: \ x -> x (\ y -> x y)
* Relevant bindings include
    x :: t2 -> t3 (bound at <interactive>:1:10)
    f :: (t2 -> t3) -> t3 (bound at <interactive>:1:5)
它至少看起来像一条类似的错误消息。这是什么t2,t3,t4,t5?同样,GHCi使用新的类型名称,以避免混淆

通过让f=…,GHCi看到x被应用于某个对象,因此它给出了x::t2->t3,其中t2是其参数的类型,t3是返回类型。它还会看到f=\x->x等等。所以f的返回类型必须是x返回的任何东西,即t3,f的参数是x。所以f::t2->t3->t3

在这些废话里面,有x应用于某个东西。所以something,即y,必须是x的参数类型,返回类型必须是x的返回类型。即.\y->xy::t2->t3。Errk:那么我们必须让x的参数类型与之相同,因为x应用于它。我们写“与”的方式是用~

然后错误消息告诉您GHCi正在尝试理解t2~t2->t3。->绑定比~。如果你试着把t2的等价物代入RHS,你会得到t2~…->t3->t3->t3无限期

您建议的f x y=等效值不等效消息/键入有点不同。但它们都是无限类型,因此不允许使用。

GHCi提示符下的:type命令是您的朋友。让我们先举第二个例子

λ> :type let g = \x -> (\y -> y) x in g
let g = \x -> (\y -> y) x in g :: p -> p
因此,g是类型良好的,并且是编写标识函数::p->p的复杂方式。具体地说,g获取一些x并将标识函数\y->y应用于x,从而得到x。GHCi在给出类型时使用了一个新的类型名p,以避免混淆。不,你的Gxy=。。。这是不等价的。用:type检查它

您可以将:type缩写为:t。那么让我们来举你的第一个例子

λ> :t let f = \x -> x (\y -> x y) in f
* Occurs check: cannot construct the infinite type: t2 ~ t2 -> t3
* In the first argument of `x', namely `(\ y -> x y)'
  In the expression: x (\ y -> x y)
  In the expression: \ x -> x (\ y -> x y)
* Relevant bindings include
    x :: t2 -> t3 (bound at <interactive>:1:10)
    f :: (t2 -> t3) -> t3 (bound at <interactive>:1:5)
它至少看起来像一条类似的错误消息。这是什么t2,t3,t4,t5?同样,GHCi使用新的类型名称,以避免混淆

通过让f=…,GHCi看到x被应用于某个对象,因此它给出了x::t2->t3,其中t2是其参数的类型,t3是返回类型。它还会看到f=\x->x等等。所以f的返回类型必须是x返回的任何东西,即t3,f的参数是x。所以f::t2->t3->t3

在这些废话里面,有x应用于 某物所以something,即y,必须是x的参数类型,返回类型必须是x的返回类型。即.\y->xy::t2->t3。Errk:那么我们必须让x的参数类型与之相同,因为x应用于它。我们写“与”的方式是用~

然后错误消息告诉您GHCi正在尝试理解t2~t2->t3。->绑定比~。如果你试着把t2的等价物代入RHS,你会得到t2~…->t3->t3->t3无限期


您建议的f x y=等效值不等效消息/键入有点不同。但它们都是无限类型,所以不允许使用。

fx=xx$=xx。它没有类型,lambda或no lambda。通过eta扩展f x y=x x y,该扩展仍然没有类型。gx=idx=x。我不能理解你的推理。@WillNess它没有排名1的类型,但它有排名2的类型:全部a。a->b->b.@AaditMShah有趣。看起来这对我们输入f没有帮助。f尽管如此:@意志力Lol,Y组合器?让我试着看看我是否能设计出一种适合的类型。但我很可能无法做到。好了,小欧米茄不能被输入。@AaditMShah我在谷歌上搜索了y combinator是否有排名2的类型,没有立即出现明显的是/否答案。当然,它可以用一个新类型来完成…fx=xx$=xx。它没有类型,lambda或no lambda。通过eta扩展f x y=x x y,该扩展仍然没有类型。gx=idx=x。我不能理解你的推理。@WillNess它没有排名1的类型,但它有排名2的类型:全部a。a->b->b.@AaditMShah有趣。看起来这对我们输入f没有帮助。f尽管如此:@意志力Lol,Y组合器?让我试着看看我是否能设计出一种适合的类型。但我很可能无法做到。好了,小欧米茄不能被输入。@AaditMShah我在谷歌上搜索了y combinator是否有排名2的类型,没有立即出现明显的是/否答案。当然可以使用新类型…删除并道歉。稍微严格一点:f x=x x x可以在GHC中使用秩2类型键入,但在标准Haskell中不能,但不能推断。我同意@AlexeyRomanov。您可以为所有a分配类型。a->b->b到f x=x。@AaditMShah啊,对。在我修改后的答案中,我选择了较短的f::forall a类型。a->b,但是你的更有用,因为它允许非底部常量函数。fxy=xxy等于正确的定义,所以不是完全错误的。不过,推导完全不符合要求。删除并道歉。稍微严格一点:Fx=Xx可以在GHC中使用秩-2类型键入,但在标准Haskell中不能,但不能推断。我同意@AlexeyRomanov。您可以为所有a分配类型。a->b->b到f x=x。@AaditMShah啊,对。在我修改后的答案中,我选择了较短的f::forall a类型。a->b,但是你的更有用,因为它允许非底部常量函数。fxy=xxy等于正确的定义,所以不是完全错误的。不过,这个推导完全不符合逻辑。