2

リアルタイム信号を収集し、派生信号を計算し、生データと派生データの両方を循環バッファーに保存するため、最後の 100 万個のサンプルのみを保持します。

すべてのシグナルの現在の値をシリアル化する必要がある場合があります。だから私は次のようなものが必要です:

type D0 a = M.Map SignalType D1

data D1 a = D1 
    { foo :: M.Map DoorType a
    , bar :: D2 a
    , baz :: a
    }

data D2 = D2 
    {
        quux :: a
    ,   zoo :: a
    }

data MyData = D0 SignalBuffer 

data CurrentSignals = D0 SignalValue

SignalBufferのシーケンスですSignalValue。ボックス化されていない浮動小数点数の配列にすることができます。Haskell はFunctorインスタンスを派生させることができるので、すべてからfmap最後にフェッチし、構造体を渡してシリアライズすることができます。SignalValueSignalBufferAeson

SignalBuffer新しいティックが到着したときにすべてのバッファに新しい値をプッシュできるように、循環バッファ API を実装するにはどうすればよいですか? メモリを節約したいので、ボックス化されていない配列を使用する必要があると思います。STUArray変更可能なボックス化されていない配列 ( ?) を使用して、配列の更新がメモリに蓄積されないようにすることは有利ですか? この設定で可変配列を使用することはまったく可能ですか? 私は変化する準備ができてMyDataおりCurrentSignals、仕事をするものは何でもします。

循環バッファを実装する方法を知っています。問題は、更新を にエレガントに適用する方法MyDataです。

みたいなことを考えている

type UpdateFunc a = MyData -> SignalValue -> Modifier SignalBuffer

updateAllBuffers :: D0 UpdateFunc -> Modifier MyData

一部の信号は、他の信号の「畳み込み」です (実際の畳み込みではなく、同様の種類の処理です)。シグナルのバッファーを更新するには、他のシグナルのバッファーにアクセスする必要があります。そのため、UpdateFunc はバッファー変更関数を受け入れて返しますMyDataSignalValue

updateAllBuffers次に「zip」D0 UpdateFuncMyDataて new を取得しますMyData

もちろんModifier、自分のタスクに合ったものを使用する準備ができています-それは関数、モナド値などです.

4

1 に答える 1

0

上記のコードで何をしようとしているのか完全には理解できませんが、IOVectorfrom Data.Vector.Unboxed.Mutableを高性能配列に使用して、循環バッファーを作成できます。

{-# LANGUAGE GADTs #-}

import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Vector.Unboxed.Mutable (IOVector, Unbox)
import qualified Data.Vector.Unboxed.Mutable as V

data CircularBuffer a where
  CircularBuffer :: Unbox a =>
    { start :: IORef Int -- index for getting an element
    , end   :: IORef Int -- index for putting an element
    , array :: IOVector a
    } -> CircularBuffer a 

newCircularBuffer :: (Unbox a) => Int -> IO (CircularBuffer a)
newCircularBuffer size = CircularBuffer <$> newIORef 0 <*> newIORef 0 <*> V.new size 

putCircularBuffer :: Unbox a => a -> CircularBuffer a -> IO ()
putCircularBuffer newEndValue (CircularBuffer _start end array) = do
  endIndex <- readIORef end
  V.write array endIndex newEndValue
  writeIORef end $! (endIndex + 1) `mod` V.length array

getCircularBuffer :: Unbox a => CircularBuffer a -> IO a
getCircularBuffer (CircularBuffer start _end array) = do
  startIndex <- readIORef start
  startValue <- V.read array startIndex
  writeIORef start $! (startIndex + 1) `mod` V.length array
  pure startValue

CircularBuffer次に、の配列内のすべてのアイテムに関数を適用する関数のようなマップを作成できます (ただし、IO になります) 。

于 2019-11-19T20:34:45.813 に答える