首页 > 解决方案 > 在 Swift 中实现 Y-Combinator

问题描述

我正在观看 Jim Weirich 的演讲:https ://www.youtube.com/watch?v=FITJMJjASUs关于在 Ruby 中实现 Y-Combinator,并在 Swift 中跟进。

我最终得到了这个函数,它可以作为高达 5 的数字的阶乘:

let error: (Int) -> Int = { x in return -1 }

let generator = { (generator: (@escaping ((Int) -> Int)) -> (Int) -> Int) in
  generator(generator(generator(generator(generator(generator(error))))))
}(  { (factorial: @escaping ((Int) -> Int)) -> (Int) -> Int in
  { (x: Int) -> Int in
    if x == 0 { return 1 }
    return x * factorial(x-1)
  }
}
)

接下来发生的事情是他删除error了 ,他的代码仍然有效:

let generator = { (generator: (@escaping ((Int) -> Int)) -> (Int) -> Int) in
  generator(generator)
} ...

在 Swift 中,这是一个编译器失败,因为generator它期望(Int) -> Int作为输入,但获得了一个generator类型。

相反,我们可以如下实现 Y 组合器:

func Y<T, R>(_ generator: @escaping (@escaping (T) -> R) -> (T) -> R) -> (T) -> R {
  return { (t: T) -> R in
    let recursiveWorker = Y(generator)
    let worker = generator(recursiveWorker)
    return worker(t)
  }
}

let factorial = Y { (factorial: @escaping (Int) -> Int) -> (Int) -> Int in
  { (x: Int) -> Int in
    if x == 0 { return 1 }
    return x * factorial(x-1)
  }
}

但是上面的问题是该Y函数在该行中引用了自己:

let recursiveWorker = Y(generator)

在我看来,这违背了这个练习的全部目的。

我的问题是:是否可以在 Swift 中实现与演讲中相同的代码?也就是说,创建一个闭包 Y-combinator?还是因为 Swift 的静态类型而这不可能?

标签: swiftrubyfunctional-programmingy-combinator

解决方案


推荐阅读