Haskell 中的 Y 组合器

发布于 2024-10-03 22:58:46 字数 957 浏览 5 评论 0原文

是否可以在 Haskell 中编写 Y Combinator

看起来它会有无限递归类型。

 Y :: f -> b -> c
 where f :: (f -> b -> c)

或者什么的。即使是简单的稍微因式分解的阶乘

factMaker _ 0 = 1
factMaker fn n = n * ((fn fn) (n -1)

{- to be called as
(factMaker factMaker) 5
-}

也会失败,并显示“发生检查:无法构造无限类型:t = t -> t2 -> t1”

(Y 组合器

(define Y
    (lambda (X)
      ((lambda (procedure)
         (X (lambda (arg) ((procedure procedure) arg))))
       (lambda (procedure)
         (X (lambda (arg) ((procedure procedure) arg)))))))

在方案中看起来像这样) 或者,更简洁地称为“

(λ (f) ((λ (x) (f (λ (a) ((x x) a))))
        (λ (x) (f (λ (a) ((x x) a))))))

对于应用顺序” 对于惰性版本来说,这

(λ (f) ((λ (x) (f (x x)))
        (λ (x) (f (x x)))))

只是一个 eta 缩写。

如果您喜欢短变量名。

Is it possible to write the Y Combinator in Haskell?

It seems like it would have an infinitely recursive type.

 Y :: f -> b -> c
 where f :: (f -> b -> c)

or something. Even a simple slightly factored factorial

factMaker _ 0 = 1
factMaker fn n = n * ((fn fn) (n -1)

{- to be called as
(factMaker factMaker) 5
-}

fails with "Occurs check: cannot construct the infinite type: t = t -> t2 -> t1"

(The Y combinator looks like this

(define Y
    (lambda (X)
      ((lambda (procedure)
         (X (lambda (arg) ((procedure procedure) arg))))
       (lambda (procedure)
         (X (lambda (arg) ((procedure procedure) arg)))))))

in scheme)
Or, more succinctly as

(λ (f) ((λ (x) (f (λ (a) ((x x) a))))
        (λ (x) (f (λ (a) ((x x) a))))))

For the applicative order
And

(λ (f) ((λ (x) (f (x x)))
        (λ (x) (f (x x)))))

Which is just a eta contraction away for the lazy version.

If you prefer short variable names.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(5

生生漫 2024-10-10 22:58:46

这是 haskell 中 y 组合器的非递归定义:

newtype Mu a = Mu (Mu a -> a)
y f = (\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)

帽子提示

Here's a non-recursive definition of the y-combinator in haskell:

newtype Mu a = Mu (Mu a -> a)
y f = (\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)

hat tip

罪歌 2024-10-10 22:58:46

Y 组合器不能使用 Hindley-Milner 类型进行类型化,Hindley-Milner 类型是 Haskell 类型系统所基于的多态 lambda 演算。您可以通过诉诸类型系统的规则来证明这一点。

我不知道是否可以通过给 Y 组合器一个更高级别的类型来输入它。这会让我感到惊讶,但我没有证据证明这是不可能的。 (关键是为 lambda 绑定的 x 确定一种合适的多态类型。)

如果您想要在 Haskell 中使用定点运算符,您可以非常轻松地定义一个,因为在 Haskell 中,let-bound具有定点语义:

fix :: (a -> a) -> a
fix f = f (fix f)

您可以以通常的方式使用它来定义函数,甚至一些有限或无限的数据结构。

还可以使用递归类型的函数来实现定点。

如果您对定点编程感兴趣,您需要阅读 Bruce McAdam 的技术报告 至此结束

The Y combinator can't be typed using Hindley-Milner types, the polymorphic lambda calculus on which Haskell's type system is based. You can prove this by appeal to the rules of the type system.

I don't know if it's possible to type the Y combinator by giving it a higher-rank type. It would surprise me, but I don't have a proof that it's not possible. (The key would be to identify a suitably polymorphic type for the lambda-bound x.)

If you want a fixed-point operator in Haskell, you can define one very easily because in Haskell, let-binding has fixed-point semantics:

fix :: (a -> a) -> a
fix f = f (fix f)

You can use this in the usual way to define functions and even some finite or infinite data structures.

It is also possible to use functions on recursive types to implement fixed points.

If you're interested in programming with fixed points, you want to read Bruce McAdam's technical report That About Wraps it Up.

怪我入戏太深 2024-10-10 22:58:46

Y 组合器的规范定义如下:

y = \f -> (\x -> f (x x)) (\x -> f (x x))

但由于 x x,它不会在 Haskell 中进行类型检查,因为它需要无限类型:

x :: a -> b -- x is a function
x :: a      -- x is applied to x
--------------------------------
a = a -> b  -- infinite type

如果类型系统允许此类递归类型,它会使类型检查变得不可判定(容易出现无限循环)。

但是,如果您强制 Y 组合器进行类型检查,例如通过使用 unsafeCoerce :: a -> b

import Unsafe.Coerce

y :: (a -> a) -> a
y = \f -> (\x -> f (unsafeCoerce x x)) (\x -> f (unsafeCoerce x x))

main = putStrLn $ y ("circular reasoning works because " ++)

这是不安全的(显然)。 rampion 的答案演示了一种在 Haskell 中编写定点组合器而不使用递归的更安全方法。

The canonical definition of the Y combinator is as follows:

y = \f -> (\x -> f (x x)) (\x -> f (x x))

But it doesn't type check in Haskell because of the x x, since it would require an infinite type:

x :: a -> b -- x is a function
x :: a      -- x is applied to x
--------------------------------
a = a -> b  -- infinite type

If the type system were to allow such recursive types, it would make type checking undecidable (prone to infinite loops).

But the Y combinator will work if you force it to typecheck, e.g. by using unsafeCoerce :: a -> b:

import Unsafe.Coerce

y :: (a -> a) -> a
y = \f -> (\x -> f (unsafeCoerce x x)) (\x -> f (unsafeCoerce x x))

main = putStrLn $ y ("circular reasoning works because " ++)

This is unsafe (obviously). rampion's answer demonstrates a safer way to write a fixpoint combinator in Haskell without using recursion.

一场信仰旅途 2024-10-10 22:58:46

这个维基页面
这个 Stack Overflow 答案似乎回答了我的问题。
稍后我会写更多的解释。

现在,我发现了关于 Mu 类型的一些有趣的事情。考虑 S = Mu Bool。

data S = S (S -> Bool)

如果将 S 视为一个集合,并且等号视为同构,则方程变为

S ⇋ S -> Bool ⇋ Powerset(S)

所以 S 是与其幂集同构的集合的集合!
但从康托尔的对角论证中我们知道,Powerset(S) 的基数总是严格大于 S 的基数,因此它们永远不是同构的。
我认为这就是为什么你现在可以定义一个定点运算符,尽管你不能没有一个定点运算符。

Oh

this wiki page and
This Stack Overflow answer seem to answer my question.
I will write up more of an explanation later.

Now, I've found something interesting about that Mu type. Consider S = Mu Bool.

data S = S (S -> Bool)

If one treats S as a set and that equals sign as isomorphism, then the equation becomes

S ⇋ S -> Bool ⇋ Powerset(S)

So S is the set of sets that are isomorphic to their powerset!
But we know from Cantor's diagonal argument that the cardinality of Powerset(S) is always strictly greater than the cardinality of S, so they are never isomorphic.
I think this is why you can now define a fixed point operator, even though you can't without one.

爱殇璃 2024-10-10 22:58:46

只是为了使 rampion 的代码更具可读性:

-- Mu :: (Mu a -> a) -> Mu a
newtype Mu a = Mu (Mu a -> a) 

w :: (Mu a -> a) -> a
w h = h (Mu h)

y :: (a -> a) -> a
y f = w (\(Mu x) -> f (w x))
-- y f = f . y f

其中 w 代表 omega 组合器 w = \x -> x xy 代表 y 组合子y = \f ->瓦特。 (转发)

Just to make rampion's code more readable:

-- Mu :: (Mu a -> a) -> Mu a
newtype Mu a = Mu (Mu a -> a) 

w :: (Mu a -> a) -> a
w h = h (Mu h)

y :: (a -> a) -> a
y f = w (\(Mu x) -> f (w x))
-- y f = f . y f

in which w stands for the omega combinator w = \x -> x x, and y stands for the y combinator y = \f -> w . (f w).

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