更好的缓存结果模式

时间:2013-03-17 01:44:44

标签: caching haskell refactoring

我现在已经运行了很多次类似的模式,容易出错(错别字可以跳过一些缓存),对我来说简直不好看。是否有更好的方法来写这样的东西?

sum_with_cache' result cache ((p1,p2,p3,p4):partitions) = let
        (cache_p1, sol1) = count_noncrossing' cache p1
        (cache_p2, sol2) = count_noncrossing' cache_p1 p2
        (cache_p3, sol3) = count_noncrossing' cache_p2 p3
        (cache_p4, sol4) = count_noncrossing' cache_p3 p4
    in sum_with_cache' (result+(sol1*sol2*sol3*sol4)) cache_p4 partitions

基本上N个操作可以更新缓存吗?

我还可以写下这样的内容:

process_with_cache' res cache _ [] = (cache, res)
process_with_cache' res cache f (x:xs) =
    let (new_cache, r) = f cache x
    in process_with_cache' (r:res) new_cache f xs
process_with_cache = process_with_cache' []

但这看起来也不干净。有没有更好的方法来编写这段代码?

1 个答案:

答案 0 :(得分:8)

另一种类似的模式是当您请求一系列命名的随机数时:

let (x, rng') = random rng''
    (y, rng)  = random rng'
in (x^2 + y^2, rng)

这正是使用状态monad是正确的方法:

import Control.Monad.State

对于(RandomGen g) => g类型的所有随机数生成器,都有一个状态monad State g,它隐式地对状态进行处理:

do x <- state random
   y <- state random
   return (x^2 + y^2)

state函数只接受s -> (a, s)类型的函数,并将其转换为State s a类型的计算,在这种情况下:

state :: (RandomGen g) => (g -> (a, g)) -> State g a

您可以使用StaterunStateevalState运行execState计算:

runState (liftA2 (\x y -> x^2 + y^2) (state random) (state random))
         (mkStdGen 0)