在NetWire 5中使用`periodic`

时间:2015-03-02 20:31:40

标签: haskell netwire

请考虑以下代码:

-- 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秒钟,但是当它更新时,很明显电线在输出停止时正在运行。也许我应该做相反的事情?

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

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

编辑:请参阅this answer了解接受答案的(劣等)替代方案。

2 个答案:

答案 0 :(得分:1)

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

stateWire . periodic 2(反过来不起作用)。

原始版本不起作用的原因是periodic在没有事件时不会禁止,而只是产生NoEvent值。而且由于你的stateWire只是忽略了它的输入,当周期线在前面时,无论是否产生事件都不会对它产生任何影响,而将周期线放在后面只意味着'定期捕获当前的快照国家',这也不是你想要的。

注意:前一段中的'Front'和'back'指的是执行顺序,而不是源代码中的布局,如果您使用.则反向组合子。

答案 1 :(得分:1)

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

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

在这种情况下,电线将改变状态,禁止2秒,然后再次更改。

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