如何在Haskell中了解嵌套Lambda函数

时间:2019-03-29 07:27:18

标签: haskell functional-programming

我试图了解Haskell中以下2个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表达式中找到。我基本上是这样理解的:f(x)= x f(y)和f(y)= y x。对于g,g(x)= g(y)x和g(y)= y。但是,由于我是Haskell的新手,所以我对这些类型的转换不是很自信。如果不正确,什么是正确的转换?

2 个答案:

答案 0 :(得分:5)

都不正确。您的解决方案使用功能

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转化为fg的更多参数。充其量,我们可以使用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将不会接受f x = x x,因为它不能被键入,除非我们使用等级2类型并显式提供f :: (forall a. a) -> b之类的类型注释。原始代码f = \x -> x (\y -> x y)遇到相同的问题。在无类型语言中也可以,例如编程语言理论中的无类型lambda演算。

答案 1 :(得分:1)

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,以避免造成混淆。没有您的g x y = ...不相等。 (使用: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)

Errk。您建议的f是否与此相同?

λ> :t let f x y = x x y in f
* Occurs check: cannot construct the infinite type:
    t3 ~ t3 -> t4 -> t5
* In the first argument of `x', namely `x'

它至少看起来像是类似的错误消息。这些t2, t3, t4, t5是什么?再次,它的GHCi使用了新鲜的名称作为类型,以避免混淆。

通过查看let f = ...,GHCi看到x被应用于某事物,因此它给出了x :: t2 -> t3,其中t2是其自变量的类型,t3是返回类型。它还显示f = \x -> x (blah)。因此,f的返回类型必须为x返回的值,即t3,并且f的参数为xf :: (t2 -> t3) -> t3

(blah)内,有x应用于某物。因此,事物(即y)必须是x的参数类型,返回类型必须是x的返回类型。即(\y -> x y) :: t2 -> t3。 Errk:那么我们必须具有x的自变量类型,因为x被应用于它。而我们写“与”相同的方法就是使用~

然后错误消息告诉您GHCi试图理解t2 ~ (t2 -> t3)。 (->~绑定更紧密。)而且,如果您尝试将t2的等效项替换为RHS,则会无限地获得t2 ~ (((... -> t3) -> t3)-> t3)的广告。

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