Итак, я написал свою собственную реализацию StateT
, потому что я не мог заставить трансформаторы правильно компилироваться в Haste. Я думаю, хотел получить javascript setInterval
, работающий внутри моей государственной монады. Вот вызов ffi: setInterval
.Функция интервала записи для монады StateT в ускорении
jsInterval :: Int -> IO() -> IO Int
jsInterval = ffi "(function(t,f){window.setInterval(f,t);})"
Я не мог думать в любом случае, чтобы получить результат m
назад после того, как она передается jsInterval
. Поэтому я попытался использовать IORefs
.
interval :: Int -> StateT s IO() -> StateT s IO Int
interval i m = StateT $ \s -> do
ref <- newIORef Nothing
id_ <- jsInterval i $ do
(_, s') <- runStateT m s
writeIORef ref (Just s')
s' <- readIORef ref
return (id_, s')
Это не работает, потому что оно хранит исходное состояние. Чтение произошло до написания. Поэтому я написал функцию, которая будет опроса в цикле до тех пор, пока не будет написано IORef
, но это просто вечно вечно.
interval :: Int -> StateT s IO() -> StateT s IO Int
interval i m = StateT $ \s -> do
ref <- newIORef Nothing
id_ <- jsInterval i $ do
(_, s') <- runStateT m s
writeIORef ref (Just s')
s' <- go ref
return (id_, s')
where
go ref = do
s <- readIORef ref
case s of
Nothing -> go ref
Just s' -> return s'
Возможно ли реализовать эту функцию? Я попробовал написать экземпляр MonadEvent
для StateT
, но это также не увенчалось успехом.
Я не думаю, что это возможно. Вы можете дождаться, когда 'setinterval' вызовет его функцию _once_ с помощью' MVar'. Но следующие вызовы функций не могут влиять на состояние внутри 'StateT'. – chi
Не связано с фактическим вопросом, который ответил @drquicksilver замечательно, но я хочу указать, что обертка 'setInterval' вручную не нужна; вы должны использовать [setTimer] (http://hackage.haskell.org/package/haste-compiler-0.5.1.3/docs/Haste.html#v:setTimer). – valderman
@valderman Я попытался это сделать, но столкнулся с аналогичной проблемой, поскольку мне не удалось реализовать MonadEvent для StateT. – DiegoNolan