2009-12-29 104 views
3

我有一个函数,是恒定的以它的参数,例如缓存功能结果f#

let is_prime x = (test) 

但它是相当大的和缓慢的。所以我希望它的结果只需计算一次,而我只是按照自己的需要经常调用它。

我试图做到这一点的方式我这么做是不是功能性的语言:

let _is_prime x = (test) 

let mutable _is_prime_primes = [] 
let mutable _is_prime_tested = [] 

let is_prime x = 
    if List.exists (fun el -> el = x) _is_prime_primes then 
     true 
    else 
     if List.exists (fun el -> el = x) _is_prime_tested then 
     false 
    else 
     let result = _is_prime x 
     if result then _is_prime_primes <- x :: _is_prime_primes 
     _is_prime_tested <- x :: _is_prime_tested 
     result 

但是我觉得我深深错误。缓存这样的结果对于函数式语言来说必须是非常普通和简单的。

+0

看到这个关于memoization的答案:http://stackoverflow.com/questions/833180/handy-f-snippets/851449#851449 – Benjol 2010-01-04 12:53:17

回答

3

这是关于这个问题的thorough thread

这里是Internet Archive链接。

+0

哦,懒惰的初始化。谢谢!它不是一个函数,它是数据,这是点 – 2009-12-29 20:20:59

+1

-1,不应该张贴链接作为答案 - 现在它已经死了。 – ebb 2013-08-20 07:15:01

+0

@ebb这是一个耻辱:(现在删除答案 – 2013-08-20 09:25:28

1

我在FSI测试中遇到了问题,但它在正常的F#项目中应该没问题。

let cache f = 
    let dict = new Dictionary<_,_>() 
    fun n -> 
     if dict.ContainsKey(n) then dict.[n] 
     else 
      let r = f n 
      dict.[n] <- r 
      r 

其签名是('a->'b) -> ('a->'b) when 'a : equality。它采用非curry函数并返回具有相同签名的另一个函数。给定的函数只对传递给它的每个唯一参数调用一次。这使得昂贵的纯功能成为可能。然而,这个缓存功能并不纯粹,而且也不是线程安全的。下面是它的用法的例子:

let slow n = // 'a -> 'a 
    System.Threading.Thread.Sleep(1000) 
    n 

let fast = cache slow // 'a -> 'a 

调用fast 1会导致睡眠中的第2第一次调用它。每个具有相同参数的连续调用将立即返回该值。

+0

谢谢!实际上我创建了一个序列并将其放入|> Seq.cache中。你的功能也很棒,谢谢,我会用它来做别的 – 2009-12-31 07:01:26