Haskell中的Y Combinator

时间:2010-11-25 03:06:37

标签: haskell y-combinator

是否可以在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)))))

这只是懒惰版本的缩减。

如果您更喜欢短变量名。

5 个答案:

答案 0 :(得分:55)

这是haskell中y-combinator的非递归定义:

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

hat tip

答案 1 :(得分:43)

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

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

如果你想在Haskell中使用定点运算符,你可以很容易地定义一个,因为在Haskell中,let-binding有定点语义:

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

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

也可以在递归类型上使用函数来实现固定点。

如果您对使用固定点进行编程感兴趣,可以阅读Bruce McAdam的技术报告That About Wraps it Up

答案 2 :(得分:25)

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's answer演示了一种在不使用递归的情况下在Haskell中编写fixpoint组合器的更安全的方法。

答案 3 :(得分:22)

this wiki pageThis Stack Overflow answer似乎回答了我的问题 我稍后会写一些解释。

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

data S = S (S -> Bool)

如果将S视为一组并且将等于符号视为同构,则等式变为

S ⇋ S -> Bool ⇋ Powerset(S)

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

答案 4 :(得分:1)

只是使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代表欧米茄组合器w = \x -> x x,而y代表y组合器y = \f -> w . (f w)