切换到包裹在 monadic 上下文中的事件
Switching to an event wrapped in monadic context
我的具体问题是这样的:
给定一个 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
原语不接受的东西。
现在,也许我以错误的方式接近它,所以这是我的一般问题。给定一个生成坐标列表和滴答事件的事件,我想生成一个可以 "use" 沿坐标移动对象的事件。所以每次 tick 触发时,位置都会更新。每次我更新坐标列表时,它都会从新列表中生成位置。
我不确定我是否正确理解了你想要的函数的语义,但在 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
发生时都会发生一个事件,并且只要该列表为非空,它就会包含(以前的)当前列表的第一个元素。
这个解决方案似乎不需要任何花哨或复杂的推理。
命名部件:
coords :: Event t [Coord]
ticks :: Event t ()
如果我们想记住最近的 Coord
直到 ticks
的下一次触发,那么我们必须在 some 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
函数列表,通过foldDyn ($)
依次应用到stack0
(只要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
我的具体问题是这样的:
给定一个 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
原语不接受的东西。
现在,也许我以错误的方式接近它,所以这是我的一般问题。给定一个生成坐标列表和滴答事件的事件,我想生成一个可以 "use" 沿坐标移动对象的事件。所以每次 tick 触发时,位置都会更新。每次我更新坐标列表时,它都会从新列表中生成位置。
我不确定我是否正确理解了你想要的函数的语义,但在 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
发生时都会发生一个事件,并且只要该列表为非空,它就会包含(以前的)当前列表的第一个元素。
这个解决方案似乎不需要任何花哨或复杂的推理。
命名部件:
coords :: Event t [Coord]
ticks :: Event t ()
如果我们想记住最近的 Coord
直到 ticks
的下一次触发,那么我们必须在 some 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
函数列表,通过foldDyn ($)
依次应用到stack0
(只要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