有没有办法在elm中缓存函数结果?

时间:2015-06-22 01:50:17

标签: elm purely-functional

我想用O(1)复杂度和O(n_max)预处理来计算第n个Fibonacci数。

要做到这一点,我需要存储以前计算的值,就像在这个C ++代码中一样:

#include<vector>
using namespace std;
vector<int> cache;
int fibonacci(int n)
{
    if(n<=0)
        return 0;
    if(cache.size()>n-1)
        return cache[n-1];
    int res;
    if(n<=2)
        res=1;
    else
        res=fibonacci(n-1)+fibonacci(n-2);
    cache.push_back(res);
    return res;
}

但它依赖于榆树不允许的副作用。

1 个答案:

答案 0 :(得分:6)

斐波

Elm中斐波纳契的正常递归定义是:

fib1 n = if n <= 1 then n else fib1 (n-2) + fib1 (n-1)

缓存

如果您想要简单的缓存,maxsnew/lazy library应该有效。它在本机JavaScript代码中使用一些副作用来缓存计算结果。它通过审查来检查本机代码是否向Elm用户公开副作用,为了便于检查,它很容易检查它是否保留了程序的语义。

您应该小心使用此库。当您创建Lazy值时,第一次强制它时需要花费时间,从那时起它就会被缓存。但是,如果您多次重新创建Lazy值,则不会共享缓存。例如,这个 DOESN&#39; T 工作:

fib2 n = Lazy.lazy (\() ->
  if n <= 1
    then n
    else Lazy.force (fib2 (n-2)) + Lazy.force (fib2 (n-1)))

工作解决方案

我通常看到的用于斐波那契的是一个懒惰的列表。我只是给出整个编译代码:

import Lazy exposing (Lazy)
import Debug

-- slow
fib1 n = if n <= 1 then n else fib1 (n-2) + fib1 (n-1)
-- still just as slow
fib2 n = Lazy.lazy <| \() -> if n <= 1 then n else Lazy.force (fib2 (n-2)) + Lazy.force (fib2 (n-1))

type List a = Empty | Node a (Lazy (List a))

cons : a -> Lazy (List a) -> Lazy (List a)
cons first rest =
    Lazy.lazy <| \() -> Node first rest

unsafeTail : Lazy (List a) -> Lazy (List a)
unsafeTail ll = case Lazy.force ll of
  Empty    -> Debug.crash "unsafeTail: empty lazy list"
  Node _ t -> t

map2 : (a -> b -> c) -> Lazy (List a) -> Lazy (List b) -> Lazy (List c)
map2 f ll lr = Lazy.map2 (\l r -> case (l,r) of
    (Node lh lt, Node rh rt) -> Node (f lh rh) (map2 f lt rt)
  ) ll lr

-- lazy list you can index into, better speed
fib3 = cons 0 (cons 1 (map2 (+) fib3 (unsafeTail fib3)))

所以fib3是一个包含所有斐波纳契数的惰性列表。因为它在内部使用fib3本身,所以它将使用相同(缓存)的惰性值,而不需要计算太多。