在 NetWire 5 中使用“周期性”

Use of `periodic` in NetWire 5

考虑以下代码:

-- this defines what our 'state' will be
data Direction = North | East | South | West deriving (Eq, Show, Enum)
data State = State Int Bool Direction deriving (Show)

initialState :: State
initialState = State 0 True North

-- a simple routine to change a state and count the number of
-- changes
nextState :: State -> State
nextState (State i _ West) = State (i+1) False South
nextState (State i _ North) = State (i+1) True East
nextState (State i b s) = State i b $ (if b then succ else pred) s

-- a wire with local state
stateWire :: Wire s () m a State
stateWire = stateWireFrom initialState
  where
    stateWireFrom s = mkSFN $ \_ -> (nextState s, stateWireFrom (nextState s))

-- let's run the wire!
main = testWire clockSession_ stateWire 

如您所想,testWire 将运行 线路尽可能快地打印输出到屏幕。但是,如果我想每 2 秒 运行 我的电线怎么办?查看文档,periodic 可能是解决方案:

-- Since periodic generates events, asSoonAs is used to 'unwrap' the Event
main = testWire clockSession_ (asSoonAs . periodic 2 . stateWire)

几乎有效。输出似乎静止了大约 2 秒,但是当它更新时,很明显当输出停止时电线正在 运行ning。也许我应该反过来做?

-- Now, this does make more sense to me...
main = testWire clockSession_ (stateWire . periodic 2)

然而,最终结果与我的第一次尝试完全一样。我在这里错过了什么?

编辑: 请参阅 以获取已接受答案的(劣等)替代方案。

问题似乎是您将 stateWire 视为连续的电线,但实际上它本身应该是事件电线。假设我正确理解了您的意图,它可能应该是 accumE (flip $ const nextState) initialState - 请参阅 the event docs for accumE - 然后您可以像这样使用它:

stateWire . periodic 2(反过来不行)。

您的原始版本不起作用的原因是 periodic 在没有事件时不会抑制,它只会产生一个 NoEvent 值。并且由于您的 stateWire 只是忽略其输入,因此当周期线在前面时,是否产生事件对它没有任何影响,而将周期线放在后面仅意味着 'periodically catch a snapshot of the current state',即也不是你想要的。

注意:上一段中的'Front'和'back'指的是执行顺序,并不是源码中的布局是反的如果您使用 . 组合器。

作为已接受答案的替代方案,也可以在不更改线路的情况下过滤掉 NoEvent

main = testWire clockSession_ (stateWire . when occurred . periodic 2)

这种情况下,线材会改变状态,抑制2秒,然后再改变。

另一个(已接受的)答案不同:电线会改变状态,然后继续产生相同的结果 2 秒,然后再次改变它。