Я хотел бы дать FRP какое-то время, и вчера я, наконец, убрал пулю и пошел, используя Netwire 5, чтобы начать (довольно произвольный выбор сам по себе , но я должен где-то начать!). Мне удалось перейти к «коду, который работает», но я заметил пару шаблонов, которые я не уверен, являются частью того, как ожидается, что библиотека будет использоваться или они являются симптомом, что-то не так.Правильное использование Netwire (5)
Я начал с this tutorial, что было достаточно, чтобы получить меня и работают довольно легко - у меня теперь есть вращающийся куб, управляемый простой «увеличивающееся число» провод:
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . 5
и приложение будет бросить курить когда «Esc» нажата, что делает использование проводов, поставляемых в netwire-input-glfw:
shouldQuit :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldQuit = keyPressed GLFW.Key'Escape
важное различие между ними в том, что spin
никогда не тормозит - она всегда должна возвращать некоторое значение - в то время как shouldQuit
постоянно останавливается; пока ключ не будет нажат, и в этом случае я выхожу из приложения.
То, что меня беспокоит, - это то, как мне приходится использовать эти провода. Прямо сейчас, это выглядит примерно так:
(wt', spinWire') <- stepWire spinWire st $ Right undefined
((qt', quitWire'), inp'') <- runStateT (stepWire quitWire st $ Right undefined) inp'
case (qt', wt') of
(Right _, _) -> return()
(_, Left _) -> return() -- ???
(_, Right x) -> --do things, render, recurse into next frame
Есть две вещи об этом шаблоне, которые заставляют меня чувствовать себя некомфортно. Во-первых, тот факт, что я передаю Right undefined
на оба звонка до stepWire
. Я думаю (если мое понимание правильное), что этот параметр предназначен для отправки событий на провод, и что, поскольку мои провода не используют какие-либо события, это «безопасно», но он чувствует себя плохо (EDIT возможно «события «здесь неправильное слово - учебник описывает его как« блокировку значений », но точка все еще стоит - я никогда не собираюсь блокировать и не использовать параметр e
в любом месте моего провода). Я посмотрел, была ли версия stepWire
для ситуации, когда вы знаете, что у вас никогда не было события, и вы бы не ответили на него, даже если у вас его есть, но он не смог его увидеть. Я попытался сделать проводы e
параметром ()
, а затем проехать Right()
всюду, что чувствует себя менее грязным, чем undefined
, но все еще не совсем кажется моим намерением.
Аналогичным образом, возвращаемое значение также равно Either
. Это идеально подходит для провода shouldQuit
, но обратите внимание, что мне нужно сопоставить шаблон по wt'
, выход провода spin
. Я действительно не знаю, что это означало бы для этого, чтобы препятствовать, поэтому я просто return()
, но я могу представить, что это становится громоздким по мере увеличения количества проводов, и снова это просто не кажется таким представителем моего намерения - иметь провод, который никогда не подавляет и на который я могу положиться, чтобы всегда придерживаться следующего значения.
Так что, хотя у меня есть код, который работает, я остаюсь с беспокойным чувством, что я «делаю это неправильно», и так как Netwire 5 довольно новичок, трудно найти примеры «идиоматического» кода, который я может проверить и посмотреть, рядом ли я с маркой. Является ли это тем, как библиотека предназначена для использования или я что-то упускаю?
EDIT: Мне удалось решить вторую проблему я упоминаю (сопоставление с образцом на Either
результате spin
) путем объединения spin
и shouldQuit
в один Wire
:
shouldContinuePlaying :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldContinuePlaying = keyNotPressed GLFW.Key'Escape
game :: (HasTime t s, Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a GL.GLfloat
game = spin . shouldContinuePlaying
Stepping этот провод дает мне гораздо более разумное возвращаемое значение - если это Left
Я могу уйти, иначе у меня есть часть данных для работы. Он также намекает на большую степень совместимости, чем мой оригинальный метод.
Мне все равно нужно передать Right undefined
в качестве входных данных для этого нового провода. По общему признанию, сейчас есть только один из них, но я все еще не уверен, что это правильный подход.
Я стараюсь не использовать эффекты в своих проводах.События передаются в «основной провод», а монада остается полиморфной. – phaazon