Haskell 为什么折叠事件和行为会占用这么多内存?

Haskell 为什么折叠事件和行为会占用这么多内存?,haskell,fold,frp,Haskell,Fold,Frp,我目前正在探索使用基本容器为FRP网络提供更多结构的可能性,从而更容易创建更复杂的事件网络 注意:我使用了,但也有同样的问题,因此我猜这个问题并不特定于所选的frp实现 在这种特殊情况下,我使用一个简单的矩阵来存储事件: newtype Matrix (w :: Nat) (h :: Nat) v a where Matrix :: Vector a -> Matrix w h v a -- deriving instances: Functor, Foldable, Trave

我目前正在探索使用基本容器为FRP网络提供更多结构的可能性,从而更容易创建更复杂的事件网络

注意:我使用了,但也有同样的问题,因此我猜这个问题并不特定于所选的frp实现


在这种特殊情况下,我使用一个简单的
矩阵
来存储
事件

newtype Matrix (w :: Nat) (h :: Nat) v a where
   Matrix :: Vector a -> Matrix w h v a

-- deriving instances: Functor, Foldable, Traversable, Applicative
Matrix
基本上只是
数据的一个薄包装。Vector
和我将使用的大多数函数基本上与相应的
Vector
函数相同。值得注意的例外是索引,但这应该是不言自明的


通过这一点,我可以定义事件矩阵,如
矩阵10 10(事件双精度)
,并能够在此基础上定义基本卷积算法:

applyStencil :: (KnownNat w, KnownNat h, KnownNat w', KnownNat h')
             => M.Matrix w' h' (a -> c)
             -> M.Matrix w h (Event a)
             -> M.Matrix w h (Event c)
applyStencil s m = M.generate stencil
  where stencil x y = fold $ M.imap (sub x y) s
        sub x0 y0 x y g = g <$> M.clampedIndex m (x0 - halfW + x) (y0 - halfH + y)
        halfW = M.width s `div` 2
        halfH = M.height s `div` 2

使用类似的方法,我可以触发~15kEvents/s,没有问题,并且在这方面有很大的净空

问题是,一旦我对网络进行采样,每秒只能从中获得两个样本:

main :: IO ()
main = do

  -- initialize the network
  sample <- start network

  forever $ do

    -- not all of the 128*128 inputs are triggered each "frame"
    triggerInputs

    -- sample the network
    mat <- sample

    -- display the matrix somehow (actually with gloss)
    displayMatrix mat
main::IO()
main=do
--初始化网络

示例我不知道问题是什么(因为我对这些FRP框架一无所知),但我不认为
traverse
sequenceA
,这可能就是他所说的那些实际上是基于列表遍历的。@dfeuer
traverse
sequenceA
来自
Data.Traversable
。我想这很清楚:)我不能说任何关于
ordrea
。但Tim是对的,每个矩阵对应于
128*128=16384
节点。使用矩阵事件
事件(矩阵…
而不是事件矩阵
矩阵(事件…
)可能会更好。在后一种情况下,我认为
Vector
根本买不到任何东西,您可以使用嵌套列表,但仍然可以获得相同的(糟糕的)性能。@Florian:只要您使用事件矩阵的简单列表,
[[Event Double]]
:-)一般来说,您观察到的一个事件只应触发
3*3=9
其他事件是正确的,但是,您需要注意观察这一点。标准的
sequenceA
combinator肯定不起作用,因为它“触及”了所有行为更新。您试图在这里编写一个增量算法,您必须确保每次“增量更新”都只对最终结果进行小的更改--运行时间与更改的大小成比例。虽然我没有分析,但在我看来,您在不必要地构建大量大的中间数据结构,特别是在
foldMapTree
中,它拆分一个列表,然后对两个延迟计算的列表执行非尾部调用操作。您可以尝试一个严格的左折叠或一个渴望评估懒惰的右折叠代替。
main :: IO ()
main = do

  -- initialize the network
  sample <- start network

  forever $ do

    -- not all of the 128*128 inputs are triggered each "frame"
    triggerInputs

    -- sample the network
    mat <- sample

    -- display the matrix somehow (actually with gloss)
    displayMatrix mat