【发布时间】:2015-05-09 05:54:34
【问题描述】:
我正在使用 netwire 包尝试了解 FRP,我有一个简单的问题。
从以下简单的线路开始,我可以每 5 秒(大约)发出一个事件
myWire :: (Monad m, HasTime t s) => Wire s () m a Float
myWire = timeF
myWire' :: (Monad m, HasTime t s) => Wire s () m a Int
myWire' = fmap round myWire
myEvent :: (Monad m, HasTime t s) => Wire s () m a (Event Int)
myEvent = periodic 5 . myWire'
这很好而且很直接,但是我接下来要做的是将每个产生的事件映射到一个线路上,然后我可以观看更新。我有一个累加器函数,如下所示:
eventList :: (Monad m, HasTime t s)
=> Wire s () m a (Event [Wire s () m a Int])
eventList = accumE go [] . myEvent
where go soFar x = f x : soFar
f x = for 10 . pure x --> pure 0
然后我引入一个新的线,它将在eventList 开始触发事件之前进行抑制,如下所示:
myList :: (Monad m, HasTime t s) => Wire s () m a [Wire s () m a Int]
myList = asSoonAs . eventList
所以我已经从事件转到包含电线列表的电线。最后,我引入了一条线来对这些线中的每一个进行步进并生成一个结果列表:
myNums :: (Monad m, HasTime t s) => Wire s () m [Wire s () m a Int] [Int]
myNums = mkGen $ \dt wires -> do
stepped <- mapM (\w -> stepWire w dt $ Right undefined) wires
let alive = [ (r, w) | (Right r, w) <- stepped ]
return (Right (map fst alive), myNums)
myNumList :: (Monad m, HasTime t s) => Wire s () m a [Int]
myNumList = myNums . myList
最后,我有我的主要例程来测试它:
main = testWire clockSession_ myNumList
我希望看到的是一个不断增长的列表,其中列表中的每个元素将显示其创建时间为 10 秒,之后元素将显示为零。相反,我得到的是不断增长的静态值列表。例如,我期望在几个步骤后看到的是
[0]
[5, 0]
[10, 5, 0]
[15, 10, 0, 0]
等等。我实际看到的是
[0]
[5, 0]
[10, 5, 0]
[15, 10, 5, 0]
所以我知道我的累加器功能正在工作:创建的每个事件都被转换成一条线。但我没有看到这些电线随着时间的推移发出不同的值。我的声明 for 10 . pure x --> pure 0 应该在时间过去后将它们切换为发射 0。
我还是 FRP 的新手,所以我可能从根本上误解了一些重要的东西(可能是这种情况。)
【问题讨论】:
-
我认为 netwire 或任何其他现代 FRP 库都不可能做到这一点。这些库通过避免提供
Monad实例或任何等效项来共同努力避免时间和空间泄漏。这意味着通常不可能将Wire ... (Wire ... a)变成Wire a。