我的具体问题是这样的:
鉴于Event t [a]
和Event t ()
(假设它是一个刻度事件),我想生成一个Event t a
,即一个从输入中给出连续项目的事件每次出现蜱事件的清单。
Reflex有以下助手:
zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
这正是我想要的,但不是将事件作为输入,而只是一个列表。鉴于我有Event t [a]
,我认为我可以生成一个包含事件的事件并且只是切换,但问题是zipListWithEven
在monadic上下文中运行,因此我可以得到:
Event t (m (Event t a))
这是switch
原语不接受的东西。
现在,也许我正以错误的方式接近它,所以这是我的一般问题。给定一个生成坐标列表和tick事件的事件,我想生成一个我可以“使用”沿着坐标移动对象的事件。所以每次勾选时,位置都会更新。每当我更新坐标列表时,它就会开始从新列表中生成位置。
答案 0 :(得分:1)
我不完全确定我是否正确理解了所需函数的语义,但在reactive-banana库中,我会解决这样的问题:
trickle :: MonadMoment m => Event [a] -> Event () -> Event a
trickle eadd etick = do
bitems <- accumB [] $ unions -- 1
[ flip (++) <$> eadd -- 2
, drop 1 <$ etick -- 3
]
return $ head <$> filterE (not . null) (bitems <@ etick) -- 4
代码的工作原理如下:
bitems
记录当前的项目列表。eadd
发生时添加项目,...... etick
发生时,会移除一个项目。etick
发生时发生的事件,并且只要该列表非空,它就包含(先前)当前列表的第一个元素。此解决方案似乎不需要任何花哨或错综复杂的推理。
答案 1 :(得分:1)
命名部分:
coords :: Event t [Coord]
ticks :: Event t ()
如果我们想要记住最近的Coord
,直到下一次ticks
被解雇,那么我们必须要在某个monad Reflex m
中。这是允许暂存Event
的monad。
您要记住的核心内容是Coord
。让我们试试这个:
data Stack a = CS {
cs_lastPop :: Maybe a
, cs_stack :: [a]
} deriving (Show)
stack0 = CS Nothing []
pop :: Stack a -> Stack a
pop (CS _ [] ) = CS Nothing []
pop (CS _ (x:xs)) = CS (Just x) xs
reset :: [a] -> Stack a -> Stack a
reset cs (CS l _) = CS l cs
在那里没有任何反应,两个函数以您在问题中提到的方式调整Stack Coord
。
驱动它的反射代码将通过指定其初始状态和修改它的所有内容来构建Dynamic t (Stack Coord)
:
coordStack <- foldDyn ($) stack0 (leftmost [
reset <$> coords
, pop <$ ticks
])
leftmost
此处列出Stack Coord -> Stack Coord
个功能,stack0
依次应用foldDyn ($)
(只要coords
并且ticks
永远不会出现在同一帧中。
在main
中推动所有这些:
main :: IO ()
main = mainWidget $ do
t0 <- liftIO getCurrentTime
-- Some make up 'coords' data, pretending (Coord ~ Char)
coordTimes <- tickLossy 2.5 t0
coords <- zipListWithEvent (\c _ -> c) ["greg","TOAST"] coordTimes
ticks <- tickLossy 1 t0
coordStack <- foldDyn ($) stack0 (leftmost [
reset <$> coords
, pop <$ ticks
])
display coordStack