Использование "периодического" в 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 секунд, но когда он обновляется, становится ясно, что провод работал, пока вывод был остановлен. Может быть, я должен сделать наоборот?
-- Now, this does make more sense to me...
main = testWire clockSession_ (stateWire . periodic 2)
Тем не менее, конечный результат в точности как моя первая попытка. Что мне здесь не хватает?
РЕДАКТИРОВАТЬ: см. Этот ответ для (низшей) альтернативы принятому ответу.
2 ответа
Кажется, проблема в том, что вы относитесь к stateWire
как будто это был непрерывный провод, но это действительно должен быть сам провод событий. Предполагая, что я правильно понял ваше намерение, это должно быть accumE (flip $ const nextState) initialState
- смотрите документацию по событиям для накопителя - тогда вы можете использовать его следующим образом:
stateWire . periodic 2
(наоборот не будет работать).
Причина, по которой ваша оригинальная версия не работает, заключается в том, что periodic
не запрещает, когда нет события, вместо этого просто производит NoEvent
значение. А так как ваш stateWire просто игнорирует его ввод, независимо от того, произведено событие или нет, для него не имеет значения, когда периодический провод находится впереди, тогда как размещение периодического провода сзади означает просто "периодически ловить снимок текущего государство ", что тоже не то, что вы хотите.
Примечание: "Front" и "Back" в предыдущем абзаце относятся к порядку выполнения, а не к макету в исходном коде, который является обратным, если вы используете .
комбинатор.
В качестве альтернативы принятому ответу также возможно отфильтровать NoEvent
, без замены провода:
main = testWire clockSession_ (stateWire . when occurred . periodic 2)
В этом случае провод изменит состояние, заблокирует на 2 секунды и затем изменит его снова.
Другой (принятый) ответ работает иначе: проводник изменит состояние, затем продолжит выдавать тот же результат в течение 2 секунд, а затем изменит его снова.