为什么这个函数的类型是(a -> a) ->一个?

发布于 2024-12-28 00:13:19 字数 469 浏览 2 评论 0原文

为什么这个函数的类型是(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

请叫√我孤独 2025-01-04 00:13:19

好吧,y 必须是 (a -> b) ->; 类型。 c,对于某些 abc 我们还不知道;毕竟,它接受一个函数 f,并将其应用于参数,因此它必须是一个接受函数的函数。

由于yf = f x(同样,对于某些x),我们知道y的返回类型必须是的返回类型f 本身。因此,我们可以稍微细化一下 y 的类型:它必须是 (a -> b) -> b 对于一些我们还不知道的 ab

要弄清楚 a 是什么,我们只需查看传递给 f 的值的类型。它是 y f,这是我们现在试图找出其类型的表达式。我们说 y 的类型是 (a -> b) -> b(对于某些ab等),因此我们可以说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 some a, b and c 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 some x), we know that the return type of y must be the return type of f itself. So, we can refine the type of y a bit: it must be (a -> b) -> b for some a and b we don't know yet.

To figure out what a is, we just have to look at the type of the value passed to f. It's y f, which is the expression we're trying to figure out the type of right now. We're saying that the type of y is (a -> b) -> b (for some a, b, etc.), so we can say that this application of y f must be of type b itself.

So, the type of the argument to f is b. 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 equivalent y f = f (f (y f)), y f = f (f (f (y f))), and so on. So, we know that we can always apply another f around the whole thing, and since the "whole thing" in question is the result of applying f to an argument, f has to have the type a -> a; and since we just concluded that the whole thing is the result of applying f to an argument, the return type of y must be that of f itself — coming together, again, as (a -> a) -> a.

夏末染殇 2025-01-04 00:13:19

仅补充两点以补充其他人的答案。

您定义的函数通常称为 fix,它是一个固定-点组合器:计算另一个点的固定点的函数 功能。在数学中,函数f的不动点是一个参数x,使得fx = x。这已经允许您推断 fix 的类型必须是 (a -> a) ->;一个; “该函数接受从 aa 的函数,并返回 a。”

您已将函数命名为 y,它似乎位于 之后Y 组合器,但这是一个不准确的名称:Y 组合器是一个特定的定点组合器,但与您在此处定义的不同。

我不明白 f (yf) 如何解析为值。

好吧,诀窍在于 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 function f is an argument x such that f x = x. This already allows you to infer that the type of fix has to be (a -> a) -> a; "function that takes a function from a to a, and returns an a."

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.

I don't get how f (y f) resolves to a value.

Well, the trick is that Haskell is a non-strict (a.k.a. "lazy") language. The calculation of f (y f) can terminate if f doesn't need to evaluate its y f argument in all cases. So, if you're defining factorial (as John L illustrates), fac (y fac) 1 evaluates to 1 without evaluating y 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.

油饼 2025-01-04 00:13:19

@ehird 在解释类型方面做得很好,所以我想通过一些示例来展示它如何解析为值。

f1 :: Int -> Int
f1 _ = 5

-- expansion of y applied to f1
y f1
f1 (y f1)  -- definition of y
5          -- definition of f1 (the argument is ignored)

-- here's an example that uses the argument, a factorial function
fac :: (Int -> Int) -> (Int -> Int)
fac next 1 = 1
fac next n = n * next (n-1)

y fac :: Int -> Int
fac (y fac)   -- def. of y
  -- at this point, further evaluation requires the next argument
  -- so let's try 3
fac (y fac) 3  :: Int
3 * (y fac) 2             -- def. of fac
3 * (fac (y fac) 2)       -- def. of y
3 * (2 * (y fac) 1)       -- def. of fac
3 * (2 * (fac (y fac) 1)  -- def. of y
3 * (2 * 1)               -- def. of fac

您可以对任何您喜欢的函数执行相同的步骤,看看会发生什么。这两个例子都收敛于值,但这并不总是发生。

@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.

f1 :: Int -> Int
f1 _ = 5

-- expansion of y applied to f1
y f1
f1 (y f1)  -- definition of y
5          -- definition of f1 (the argument is ignored)

-- here's an example that uses the argument, a factorial function
fac :: (Int -> Int) -> (Int -> Int)
fac next 1 = 1
fac next n = n * next (n-1)

y fac :: Int -> Int
fac (y fac)   -- def. of y
  -- at this point, further evaluation requires the next argument
  -- so let's try 3
fac (y fac) 3  :: Int
3 * (y fac) 2             -- def. of fac
3 * (fac (y fac) 2)       -- def. of y
3 * (2 * (y fac) 1)       -- def. of fac
3 * (2 * (fac (y fac) 1)  -- def. of y
3 * (2 * 1)               -- def. of fac

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.

原野 2025-01-04 00:13:19

让我讲述一下组合器。它称为“定点组合器”,具有以下属性:

属性:“定点组合器”采用函数 f :: (a -> a)发现该函数的“不动点”x :: a,使得fx == x。定点组合器的某些实现在“发现”方面可能更好或更差,但假设它终止,它将产生输入函数的定点。任何满足该属性的函数都可以称为“不动点组合器”。

将此称为“固定点组合器”y。根据我们刚才所说的,以下内容是正确的:

-- as we said, y's input is f :: a -> a, and its output is x :: a, therefore
y :: (a -> a) -> a

-- let x be the fixed point discovered by applying f to y
y f == x -- because y discovers x, a fixed point of f, per The Property
f x == x -- the behavior of a fixed point, per The Property

-- now, per substitution of "x" with "f x" in "y f == x"
y f == f x
-- again, per substitution of "x" with "y f" in the previous line
y f == f (y f)

所以你就可以了。您已经根据定点组合器的基本属性定义了 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 that f 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:

-- as we said, y's input is f :: a -> a, and its output is x :: a, therefore
y :: (a -> a) -> a

-- let x be the fixed point discovered by applying f to y
y f == x -- because y discovers x, a fixed point of f, per The Property
f x == x -- the behavior of a fixed point, per The Property

-- now, per substitution of "x" with "f x" in "y f == x"
y f == f x
-- again, per substitution of "x" with "y f" in the previous line
y f == f (y f)

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 that y f discovers x, you can assume that x 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文