Я делаю холст-игру с использованием PureScript, и мне интересно, как лучше всего обработать прослушиватели событий, в частности, выполнение обратных вызовов в пользовательском стеке монады. Это моя игра стек ...(PureScript) Как запустить обратный вызов прослушивателя событий DOM в монадическом контексте, отличном от Eff?
type BaseEffect e = Eff (canvas :: CANVAS, dom :: DOM, console :: CONSOLE | e)
type GameState = { canvas :: CanvasElement, context :: Context2D, angle :: Number }
type GameEffect e a = StateT GameState (BaseEffect e) a
То, что я хотел бы сделать, это изменить свойство «угол» в GameState при нажатии любой клавиши (только для целей развития, так что я могу настроить графику). Это моя функция обратного вызова ...
changeState :: forall e. Event -> GameEffect e Unit
changeState a = do
modify \s -> s { angle = s.angle + 1.0 }
liftEff $ log "keypress"
pure unit
Однако addEventListener и eventListener выглядят как они предназначены для использования только с Eff, так что следующее не наберете проверить ...
addEventListener
(EventType "keypress")
(eventListener changeState)
false
((elementToEventTarget <<< htmlElementToElement) bodyHtmlElement)
Я думал, что могу определить addEventListener и eventListener самостоятельно, и импортировать их с помощью внешних интерфейсов функций (с помощью Eff для GameEffect). Это напечатано проверено, но вызвало ошибку консоли, когда я попытался запустить в браузере.
foreign import addEventListener :: forall e. EventType -> EventListener e -> Boolean -> EventTarget -> GameEffect e Unit
foreign import eventListener :: forall e. (Event -> GameEffect e Unit) -> EventListener e
Каков наилучший способ обработки обратных вызовов в стеке монады?
Мне удалось заставить его работать, но только для одного нажатия клавиши и нажатия клавиши, казалось, блокировали рендеринг графики. После первого нажатия клавиши потребитель закрывается и выводит графику. Я думаю, мне нужно создать экземпляр 'Parallel' для GameEffect (завернутый в newtype), поэтому я могу использовать' CR.runProcess $ connect производитель-потребитель'. Это звучит так, будто я на правильном пути? – Albtzrly
Упс! «Пользователь» должен был быть определен следующим образом: 'навсегда $ lift <<< changeState = << CR.await', с' forever', исходящим из 'Control.Monad.Rec.Class'. –
Блокировка немного сложнее решить, так как простой ответ будет [«просто fork it»] (https://github.com/slamdata/purescript-fork), однако нет экземпляра forking 'StateT'. Возможно, вы могли бы придумать что-то с 'newtype' для GameEffect. Я немного удивлен тем, что он блокирует рендеринг, поскольку это предполагает вызов 'setupListener' в цикле рендеринга? Похоже, вы должны просто сделать это один раз в конце настройки. В принципе, у меня нет хорошего ответа на этот бит, извините! –