我现在已经运行了很多次类似的模式,容易出错(错别字可以跳过一些缓存),对我来说简直不好看。是否有更好的方法来写这样的东西?
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' []
但这看起来也不干净。有没有更好的方法来编写这段代码?
答案 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
您可以使用State
,runState
或evalState
运行execState
计算:
runState (liftA2 (\x y -> x^2 + y^2) (state random) (state random))
(mkStdGen 0)