所以我编写了自己的实现,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
但这也没有成功。