需要详细解释Swift中的Memoize实现(WWDC 14,会话404)

需要详细解释Swift中的Memoize实现(WWDC 14,会话404),swift,Swift,Dave Abrahams展示了memoize()的一个非常有趣的版本: 实际上,它或多或少是memoize的标准实现。你有一张输入和输出的地图(这里是字典)。如果我们在字典中已经有了输入,请查找并返回输出。如果我们没有,计算它,存储在字典中,然后返回 memoize函数只需调用一次,因为它将任何函数(正确类型的函数)转换为该函数的memoize版本。从那时起,你只需称之为记忆版。这是一个函数,它接受一个函数作为参数,并返回一个新函数作为结果。返回的函数只是将对原始函数的调用封装在我在上一段中描

Dave Abrahams展示了memoize()的一个非常有趣的版本:


实际上,它或多或少是
memoize
的标准实现。你有一张输入和输出的地图(这里是字典)。如果我们在字典中已经有了输入,请查找并返回输出。如果我们没有,计算它,存储在字典中,然后返回

memoize
函数只需调用一次,因为它将任何函数(正确类型的函数)转换为该函数的memoize版本。从那时起,你只需称之为记忆版。这是一个函数,它接受一个函数作为参数,并返回一个新函数作为结果。返回的函数只是将对原始函数的调用封装在我在上一段中描述的备忘录中

很难知道还有什么要告诉你,因为我不知道你觉得什么部分很难理解。我的书非常详细地介绍了函数如何在Swift中传递。如果您不理解将函数作为参数传递给函数的概念,请阅读。如果您不理解函数返回函数的概念,请阅读


Swift有闭包,因此我们可以在返回函数的环境空间中维护字典(通过在返回函数外部定义字典,以便捕获字典)。如果你觉得这是很难理解的,这里有一个例子。

谢谢你,马特。这个解释很有帮助。还有一件很难理解的事情是var结果的声明:(T->U)。如此声明的动机是什么?如果我没记错的话,他会详细说明这一点。他只是在解决Swift语言(在演讲时)的一些奇怪限制。是的,看起来这是确保在初始化变量之前使用变量的方法。例如,我们倾向于在被重新分配给结果本身的块中使用该结果变量。Matt,我已经用一个使用局部函数的干净实现编辑了我的问题。这使得代码更容易阅读。你完全正确-在Swift 2.0之前,局部函数不能是自引用的,所以他必须解决这个问题(相当聪明)。在Swift 2.0中,局部函数可以是自引用的、相互引用的,甚至是递归的
func Memoize<T:Hashable, U> (body: (T -> U, T ) -> U ) -> (T) -> U {

      var memo = Dictionary <T, U> ()

      var result: (T -> U)!

      result = { x in
            if let q = memo[x] { return q }
            let r = body(result, x)
            memo[x] = r
            return r
      }

      return result
}

let factorial = Memoize { (factorial, x) in
                x == 0 ? 1 : x * factorial(x - 1)
        }
func Memoize<T:Hashable, U> (body: @escaping ((T) -> U, T ) -> U ) -> (T) -> U {

    var memo = Dictionary <T, U> ()

    func result(x : T) -> U {
        if let q = memo[x] { return q }
        let r = body(result, x)
        memo[x] = r
        return r
    }

    return result
}