为什么这个函数的类型是(a -> a) ->一个?
为什么这个函数的类型是(a -> a) ->一个?
Prelude> let y f = f (y f)
Prelude> :t y
y :: (t -> t) -> t
它不应该是无限/递归类型吗? 我本来想尝试用语言表达我认为它应该是什么样的类型,但由于某种原因我无法做到这一点。
y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS?
我不明白 f (yf) 如何解析为一个值。以下内容对我来说更有意义:
Prelude> let y f x = f (y f) x
Prelude> :t y
y :: ((a -> b) -> a -> b) -> a -> b
但它仍然令人困惑。这是怎么回事?
Why is the type of this function (a -> a) -> a?
Prelude> let y f = f (y f)
Prelude> :t y
y :: (t -> t) -> t
Shouldn't it be an infinite/recursive type?
I was going to try and put into words what I think it's type should be, but I just can't do it for some reason.
y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS?
I don't get how f (y f) resolves to a value. The following makes a little more sense to me:
Prelude> let y f x = f (y f) x
Prelude> :t y
y :: ((a -> b) -> a -> b) -> a -> b
But it's still ridiculously confusing. What's going on?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,
y
必须是(a -> b) ->; 类型。 c
,对于某些a
、b
和c
我们还不知道;毕竟,它接受一个函数f
,并将其应用于参数,因此它必须是一个接受函数的函数。由于
yf = f x
(同样,对于某些x
),我们知道y
的返回类型必须是的返回类型f 本身。因此,我们可以稍微细化一下
y
的类型:它必须是(a -> b) -> b
对于一些我们还不知道的a
和b
。要弄清楚
a
是什么,我们只需查看传递给f
的值的类型。它是y f
,这是我们现在试图找出其类型的表达式。我们说y
的类型是(a -> b) -> b
(对于某些a
、b
等),因此我们可以说y f
的这个应用程序必须是类型b
本身。因此,
f
的参数类型是b
。将它们全部放回一起,我们得到(b -> b) -> b
— 当然,这与(a -> a) ->; 是一样的。一个。
这是一个更直观但不太精确的观点:我们说 yf = f (yf),我们可以将其扩展为等效的 yf = f (f (yf)) 、
yf = f (f (f(yf)))
等等。因此,我们知道我们总是可以在整个事物周围应用另一个f
,并且由于所讨论的“整个事物”是将f
应用于参数的结果,< code>f 必须具有类型a ->一个
;由于我们刚刚得出结论,整个事情是将f
应用于参数的结果,因此y
的返回类型必须是f
的返回类型本身 - 再次组合在一起,作为(a -> a) ->一个。
Well,
y
has to be of type(a -> b) -> c
, for somea
,b
andc
we don't know yet; after all, it takes a function,f
, and applies it to an argument, so it must be a function taking a function.Since
y f = f x
(again, for somex
), we know that the return type ofy
must be the return type off
itself. So, we can refine the type ofy
a bit: it must be(a -> b) -> b
for somea
andb
we don't know yet.To figure out what
a
is, we just have to look at the type of the value passed tof
. It'sy f
, which is the expression we're trying to figure out the type of right now. We're saying that the type ofy
is(a -> b) -> b
(for somea
,b
, etc.), so we can say that this application ofy f
must be of typeb
itself.So, the type of the argument to
f
isb
. Put it all back together, and we get(b -> b) -> b
— which is, of course, the same thing as(a -> a) -> a
.Here's a more intuitive, but less precise view of things: we're saying that
y f = f (y f)
, which we can expand to the equivalenty f = f (f (y f))
,y f = f (f (f (y f)))
, and so on. So, we know that we can always apply anotherf
around the whole thing, and since the "whole thing" in question is the result of applyingf
to an argument,f
has to have the typea -> a
; and since we just concluded that the whole thing is the result of applyingf
to an argument, the return type ofy
must be that off
itself — coming together, again, as(a -> a) -> a
.仅补充两点以补充其他人的答案。
您定义的函数通常称为
fix
,它是一个固定-点组合器:计算另一个点的固定点的函数 功能。在数学中,函数f
的不动点是一个参数x
,使得fx = x
。这已经允许您推断fix
的类型必须是(a -> a) ->;一个
; “该函数接受从a
到a
的函数,并返回a
。”您已将函数命名为
y
,它似乎位于 之后Y 组合器,但这是一个不准确的名称:Y 组合器是一个特定的定点组合器,但与您在此处定义的不同。好吧,诀窍在于 Haskell 是一种非严格(又名“惰性”)语言。如果
f
在所有情况下都不需要计算其y f
参数,则f (yf)
的计算可以终止。因此,如果您定义阶乘(如 John L 所示),fac (y fac) 1
的计算结果为 1,而不计算y fac
。严格语言无法做到这一点,因此在这些语言中您无法以这种方式定义定点组合器。在这些语言中,教科书的定点组合器是 Y 组合器本身。
Just two points to add to other people's answers.
The function you're defining is usually called
fix
, and it is a fixed-point combinator: a function that computes the fixed point of another function. In mathematics, the fixed point of a functionf
is an argumentx
such thatf x = x
. This already allows you to infer that the type offix
has to be(a -> a) -> a
; "function that takes a function froma
toa
, and returns ana
."You've called your function
y
, which seems to be after the Y combinator, but this is an inaccurate name: the Y combinator is one specific fixed point combinator, but not the same as the one you've defined here.Well, the trick is that Haskell is a non-strict (a.k.a. "lazy") language. The calculation of
f (y f)
can terminate iff
doesn't need to evaluate itsy f
argument in all cases. So, if you're defining factorial (as John L illustrates),fac (y fac) 1
evaluates to 1 without evaluatingy fac
.Strict languages can't do this, so in those languages you cannot define a fixed-point combinator in this way. In those languages, the textbook fixed-point combinator is the Y combinator proper.
@ehird 在解释类型方面做得很好,所以我想通过一些示例来展示它如何解析为值。
您可以对任何您喜欢的函数执行相同的步骤,看看会发生什么。这两个例子都收敛于值,但这并不总是发生。
@ehird's done a good job of explaining the type, so I'd like to show how it can resolve to a value with some examples.
You can follow the same steps with any function you like to see what will happen. Both of these examples converge to values, but that doesn't always happen.
让我讲述一下组合器。它称为“定点组合器”,具有以下属性:
属性:“定点组合器”采用函数
f :: (a -> a)
和发现该函数的“不动点”x :: a
,使得fx == x
。定点组合器的某些实现在“发现”方面可能更好或更差,但假设它终止,它将产生输入函数的定点。任何满足该属性的函数都可以称为“不动点组合器”。将此称为“固定点组合器”
y
。根据我们刚才所说的,以下内容是正确的:所以你就可以了。您已经根据定点组合器的基本属性定义了
y
:yf == f (yf)
。您可以假设x
表示发散计算,但仍然得出相同的结论 (iinm),而不是假设y f
发现x
。由于您的函数满足该属性,因此我们可以得出结论,它是一个定点组合器,并且我们声明的其他属性(包括类型)适用于您的函数。
这并不是一个可靠的证据,但我希望它能提供额外的见解。
Let me tell about a combinator. It's called the "fixpoint combinator" and it has the following property:
The Property: the "fixpoint combinator" takes a function
f :: (a -> a)
and discovers a "fixed point"x :: a
of that function such thatf x == x
. Some implementations of the fixpoint combinator might be better or worse at "discovering", but assuming it terminates, it will produce a fixed point of the input function. Any function that satisfies The Property can be called a "fixpoint combinator".Call this "fixpoint combinator"
y
. Based on what we just said, the following are true:So there you go. You have defined
y
in terms of the essential property of the fixpoint combinator:y f == f (y f)
. Instead of assuming thaty f
discoversx
, you can assume thatx
represents a divergent computation, and still come to the same conclusion (iinm).Since your function satisfies The Property, we can conclude that it is a fixpoint combinator, and that the other properties we have stated, including the type, are applicable to your function.
This isn't exactly a solid proof, but I hope it provides additional insight.