我該如何改進下面的滾動實施?如何改進haskell滾動和實現?
type Buffer = State BufferState (Maybe Double)
type BufferState = ([Double] , Int, Int)
-- circular buffer
buff :: Double -> Buffer
buff newVal = do
(list, ptr, len) <- get
-- if the list is not full yet just accumulate the new value
if length list < len
then do
put (newVal : list , ptr, len)
return Nothing
else do
let nptr = (ptr - 1) `mod` len
(as,(v:bs)) = splitAt ptr list
nlist = as ++ (newVal : bs)
put (nlist, nptr, len)
return $ Just v
-- create intial state for circular buffer
initBuff l = ([] , l-1 , l)
-- use the circular buffer to calculate a rolling sum
rollSum :: Double -> State (Double,BufferState) (Maybe Double)
rollSum newVal = do
(acc,bState) <- get
let (lv , bState') = runState (buff newVal) bState
acc' = acc + newVal
-- subtract the old value if the circular buffer is full
case lv of
Just x -> put (acc' - x , bState') >> (return $ Just (acc' - x))
Nothing -> put (acc' , bState') >> return Nothing
test :: (Double,BufferState) -> [Double] -> [Maybe Double] -> [Maybe Double]
test state [] acc = acc
test state (x:xs) acc =
let (a,s) = runState (rollSum x) state
in test s xs (a:acc)
main :: IO()
main = print $ test (0,initBuff 3) [1,1,1,2,2,0] []
緩衝區使用狀態monad實現循環緩衝區。 rollSum再次使用State monad來跟蹤滾動總和值和循環緩衝區的狀態。
- 我怎麼能使這更優雅?
- 我想實現其他功能,如滾動平均值或差異,我可以做些什麼來簡化它?
謝謝!
編輯
我忘了提我使用的是循環緩衝區,因爲我打算使用上線和工藝更新的代碼,他們到達 - 因此需要記錄狀態。像
newRollingSum = update rollingSum newValue
我沒有讀到源代碼,但是我在替換測試列表後,運行了'main',其中應該清楚地顯示行爲,即'[1,10,100,1000,10000,100000]' 。結果顯示它增加了三個元素,從索引3開始,然後是2,然後是1;但從不從索引0開始。這是故意的嗎? –