所以我编写了自己的实现,StateT因为我无法让转换器在 Haste 中正确编译。我想想让 javascriptsetInterval在我的状态 monad 中工作。这是对 ffi 的调用setInterval。
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我尝试编写一个for的实例,StateT但这也没有成功。