Swift — memoize()逐步

最近,我一直在阅读有关Swift 3未来的文章。 对在服务器上使用Swift以及在该方面完成的工作特别感兴趣。

迅捷轨迹🚀

Swift具有巨大的潜力,可以成为构建从VR到移动到服务器再到AI 主流语言。 仍然缺少一些关键的构建块,但已经奠定了坚实的基础。 其中,可以说是最重要的功能支持 ,从第一天开始就随语言一起提供。

功能迅捷

语言结构很好地表达了功能支持,这使得一些疯狂的热门功能实现成为一个例子,其中一个示例就是在WWDC’14 Session 404 – Advanced Swift中引入的备忘录功能(讨论从00:38开始)。

在这篇文章中,我希望探讨memoize的性质并解释其工作原理,将其从WWDC’17的“高级”轨道移至“基本”轨道。

记住

乍一看, memoize's实现看起来像Brainfuck启发的Hello World,但请放心-它是Swift。 纯功能性Swift😼

步骤2:递归记忆

为什么此版本的memoize递归的要点是,将工作闭包作为参数传递给它自己 ,这使工作闭包可以对自身的memoize'd版本进行递归调用。

这有资格获得令人赞叹的史诗般的胜利🎆

14号线

使用尾随闭包语法,我传递了2参数工作闭包以进行memoize. memoize的结果(环绕式闭合)存储在名为factorial的参数中。

从工作闭包体内 factorial(x-1) 的调用 是指传递给闭包的参数,它与 let factorial 命名 完全无关

15号线

let factorial类型为(Int) -> Int

  • 推断输入Int是因为发现Int Type符合以下要求:
    1.符合Hashable协议。
    2.支持==*操作。
  • 之所以推断Return Int是因为在返回之前没有执行任何类型转换。

1号线

memoize的递归支持版本还使用2个类型占位符: T, U.

由于我们已经确定factorial类型为(Int) -> Intfactorial memoize的占位符变为T=Int, U=Int

memoize接受类型((T)->U, T) -> U 1个输入参数,即闭包。 work是第15行上的调用方传递的闭包。

memoize的返回类型仍然是(T) -> U (包装器关闭)。 专用于factorial它变为(Int) -> Int.

4号线

在这里,我定义了一个嵌套函数。 嵌套函数只是命名为闭包。 使用嵌套函数在这里很有用,因为它带有(T) -> U类型,这是Swift类型强制通过第6行的检查所必需的。

6号线

小心 独角兽🦄

调用work进行实际计算。 work是我在第15行定义的闭包,它接受2个参数:

  • wrap工作闭包中对函数的递归调用(阅读: 魔术 )。 工作闭包能够再次调用wrap ,并且由于wrap引用work ,因此结果是递归调用,以在两者之间使用缓存层—就像非递归版本的memoize行为一样,仅使用内置的递归✌️。
  • x是值调用者代码,随后的递归调用作为输入参数传递以计算结果。

步骤2:摘要

factorial是由memoize.的递归版本生成的嵌套wrap函数memoize. wrap函数保留对内部调用的工作闭包的引用,并将引用传递给自身。

递归记忆简化

包装函数保留对原始函数的引用,并且对于递归的每次迭代, 包装函数都会对其自身传递一个引用,以便原始函数将再次调用它,从而启用递归。

例如:

想想AB.的引用B.

  1. 调用者代码要求A计算值a
  2. A呼叫B ,并传递:
    a —计算结果的请求值,以及
    A对自身的引用。
  3. 剩下的B决定它如何处理计算请求,它可以返回 a的结果或再次调用 B ,这将循环返回A ,即将递归堆栈加1。

请注意,当B将递归请求返回给A ,除了a-1的下一个计算值外,它不会传递其他任何内容。 这是因为A拥有对B以及对B本身所需的所有引用,从而使实现不仅高效而且美观。