2015-03-02 2 views
1

Рассмотрим следующий код:Использование `periodic` в 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) 

Однако конечный результат в точности совпадает с моей первой попыткой. Что мне здесь не хватает?

EDIT: См. this answer для (младшей) альтернативы принятому ответу.

+0

Я бы рекомендовал вам опубликовать свое редактирование вместо ответа; Ответ на ваши собственные вопросы разрешен в stackoverflow и имеет больше смысла, чем ответ на вопрос. Кроме того, вероятно, нет необходимости копировать мой ответ, если вы не хотите подчеркнуть некоторую разницу между ними. – Cubic

ответ

1

Проблема заключается в том, что вы обрабатываете свой stateWire, как если бы это был непрерывный провод, но он действительно должен быть проводником событий. Предполагая, что я правильно понял ваше намерение, вероятно, должно быть accumE (flip $ const nextState) initialState - см. the event docs для accumE - тогда вы можете использовать его следующим образом:

stateWire . periodic 2 (наоборот, не работает).

Причина, по которой ваша оригинальная версия не работает, заключается в том, что periodic не блокирует, когда нет события, вместо этого он просто производит значение NoEvent. И так как ваше stateWire просто игнорирует его вход, независимо от того, производится ли событие, не имеет для него никакого значения, когда периодический провод находится впереди, тогда как статический провод в задней части просто означает «периодически захватывать моментальный снимок текущего state ', что также не то, что вы хотите.

Примечание: «Фронт» и «назад» в предыдущем абзаце, относятся к порядку исполнения, а не макет в исходном коде, который находится в обратном направлении, если вы используете . комбинатор.

+0

Я думаю, вы имеете в виду 'accumE (flip $ const nextState) initialState'. Это работает, но это заставило меня понять, что я могу заставить его работать с непрерывным проводом, если я его фильтрую с 'когда произошел'. –

+1

Да, это была опечатка. Исправлено. Для этого требуется небезопасное.Событие и IMHO изменение состояния, которое зависит от события, должно (должно быть), конечно, самим событием. Выполняя это, вы внезапно получаете провод, который утверждает, что он является непрерывным, но на самом деле не дает значений для какого-либо интервала. – Cubic

+0

Вы правы. Мышление в событиях действительно кажется правильным способом моделирования этой проблемы. Также отредактировал мой вопрос в соответствии с вашими отзывами. Благодаря! –

1

В качестве альтернативы принятого ответа, это также можно отфильтровать NoEvent, не меняя провода:

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

В этом случае провод будет изменять состояние, блокировки в течение 2 секунд а затем снова измените его.

Другие (принятые) ответы работают разные: провод изменит состояние, затем продолжит выдавать тот же результат в течение 2 секунд, а затем снова изменить его.

Смежные вопросы