1
23
一如既往,延续产生了一个优雅的追尾解决方案:
有两种测试。首先,这个演示调用F(4)可以根据需要缓存F(4)、F(3)、F(2)、F(1)。
然后,注释掉
下一步,我想,把记忆分解和阶乘分离开来:
编辑
|
2
15
记忆尾部递归函数的困境当然是,当尾部递归函数
调用本身时,不允许对递归调用的结果执行任何操作,包括将其放入缓存。狡猾的;那我们该怎么办? 这里的关键是,由于递归函数不允许对递归调用的结果执行任何操作,因此递归调用的所有参数的结果都是相同的!因此,如果递归调用跟踪是这样的
实用注释:上面的阶乘示例说明了一种通用技术。它是非常无用的,因为它是非常充分的阶乘函数缓存的顶级
注意,在这个例子中,当我们从非尾部递归阶乘到尾部递归阶乘时,我们利用了乘法是结合的和交换的这一事实-尾部递归阶乘执行一组不同于非尾部递归阶乘的乘法。 事实上,存在一种从非尾部递归到尾部递归算法的通用技术,它产生一个等价于tee的算法。这种技术被称为“连续传递变换”。沿着这条路线,你可以使用一个非尾部递归记忆阶乘,通过一个机械变换得到一个尾部递归记忆阶乘。关于这个方法的解释,请看布莱恩的答案。 |
3
8
我不确定是否有更简单的方法,但一种方法是创建一个记忆y组合器:
然后,您可以使用此组合符代替“let rec”,第一个参数表示要递归调用的函数:
编辑
正如米提亚指出的,
不幸的是,插入到每个递归调用中的机器有点繁重,因此需要深度递归的未记忆输入的性能可能会有点慢。但是,与其他一些解决方案相比,它的优点是对递归函数的自然表达式的更改非常小:
编辑
以前,我们的回忆录过程是这样的:
现在,我们需要考虑一个事实
但是,如果我们愿意更改第一个参数的返回类型(从
同样,如果我们有一个合适的计算表达式来构建CPS函数,我们可以这样定义递归函数:
这与Brian所做的完全相同,但我发现这里的语法更容易理解。为了使这项工作顺利进行,我们只需要以下两个定义:
|
4
3
kvb的解决方案返回相同的结果,就像这个函数一样直接记忆。
测试源代码。
|
5
0
|
Thomas · 使类型别名在F中不可互换# 2 年前 |
sdgfsdh · 我该怎么说。使用异步转换函数进行收集? 6 年前 |
Soldalma · 我可以实例化包含顶级副作用值的类吗? 6 年前 |
matekus · F#-包含数字的字符串的自然排序 6 年前 |
matekus · F#类型匹配-无法创建映射或匹配记录 6 年前 |
Rob Lyndon · 未找到F#ProvidedTypes文件 6 年前 |
red-swan · 如何将intro ML.Net演示翻译为F#? 6 年前 |
jkone27 · F#-在编译时从字符串生成简单的空类型 6 年前 |