How is this fibonacci-function memoized?
这个斐波那契函数是通过什么机制记忆的?
1 2 3 4 |
在相关的注释中,为什么这个版本不是?
1 2 3 4 |
号
haskell中的评估机制是按需进行的:当需要一个值时,它会被计算出来,并在需要时随时准备好。如果我们定义了某个列表,
这就是"通过名单"的伎俩所利用的。在正常的双递归Fibonacci定义中,
1 |
诀窍是使该列表被创建,并使该列表在对
第一个版本定义了一个单态常量,第二个版本定义了一个多态函数。多态函数不能对它可能需要服务的不同类型使用相同的内部列表,因此不需要共享,即不需要记忆。
在第一个版本中,编译器对我们很慷慨,去掉了常量子表达式(
(编辑:)考虑这些重新写入:
1 2 3 4 5 6 7 |
号
因此,实际情况似乎是关于嵌套的范围定义。第1个定义没有外部作用域,第3个定义小心不要调用外部作用域
每次新调用
但是,没有什么能阻止编译器认识到上述任何版本中的内部定义实际上独立于外部
最终,取决于使用的编译器和编译器优化,以及如何测试它(在ghci中加载文件,是否编译,是否使用-o2,或独立),以及它是否是单态或多态类型,行为可能会完全改变-是否显示局部(每次调用)共享(即每次调用的线性时间),记忆化(即,第一次调用的线性时间,具有相同或较小参数的后续调用的0次),或者根本不共享(指数时间)。
简短的回答是,这是一个编译器的东西。:)
我不完全确定,但这里有一个有根据的猜测:
编译器假设
没有
它完全是内存化的,因为递归调用只需要在列表中查找一个值。由于
它本质上是一种基于GHC懒惰语义的智能、低成本的动态编程形式。我认为该标准只指定它必须是非严格的,因此兼容的编译器可能会将此代码编译为非memoize。然而,在实践中,每一个合理的编译器都是懒惰的。
有关第二种情况的工作原理的更多信息,请阅读了解递归定义的列表(fibs中的zipWith)。
首先,使用ghc-7.4.2,用
这是由于单态限制。
第一个是由一个简单的模式绑定(只有名称,没有参数)绑定的,因此通过单态限制,它必须得到一个单态类型。推断类型为
并且这样的约束(在没有默认声明的情况下)被默认到
号
因此,只有一个列表(类型为
第二个是用一个函数参数定义的,因此它仍然是多态的,如果内部列表是跨调用的Memoised,则必须为
在禁用单态限制或具有相同类型签名的情况下编译这两个版本,并且两个版本的行为完全相同。(对于旧的编译器版本,这不是真的,我不知道是哪个版本先做的。)
你不需要对haskell使用memoize函数。只有经验编程语言才需要这些函数。然而,哈斯克尔是功能语言和…
所以,这是非常快速的斐波那契算法的例子:
1 |
ZipWith是标准序曲的功能:
1 2 3 |
。
测试:
输出:
1 | [1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,12200160415121876738,19740274219868223167,31940434634990099905,51680708854858323072,83621143489848422977,135301852344706746049,218922995834555169026,354224848179261915075,573147844013817084101] |
。
经过时间:0.00018s