所以我编写了自己的 initial begin
forever begin
clk=0;
#5
clk=1;
#5
clk=0;
end
end
实现,因为我无法在Haste中正确编译变换器。我想想让javascript StateT
在我的状态monad中工作。这是对setInterval
的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
的实例,但这也不成功。
答案 0 :(得分:3)
您传递给FFI&#39; ed jsInterval
的IO操作只是一个简单的IO操作。如果您使用runStateT
实施该操作,那么您只需运行一点“本地”操作即可。 StateT
。它与封闭代码无关。
这是回调和monad堆栈的一般问题 - 回调(在IO(
参数到jsInterval
是一个回调的意义上)在定义中选择了固定的monad并且它们没有推广你可能在其他地方使用的其他monadic效应的方法。
由于回调 - 一般来说 - 可以在任何时候调用,包括一次多次,在不同的线程中,在调用函数完成并且其状态被破坏之后 - 你可以看到这是一个难以解决的问题。一般。
正如您所尝试的那样,务实的答案是使用IORef
;在封闭操作中创建IORef
并让回调修改它。如果您愿意,您仍然可以用StateT
样式编写回调 - 只需从IORef
中提取状态并将其传递给runStateT
。您的代码没有这样做,您只是从顶层引用参数s
:您需要使用IORef,如下所示:
id_ <- jsInterval i $ do
current_s <- readIORef ref
(_, new_s) <- runStateT m current_s
writeIORef ref (new_s)
除非您准备好教授行动Maybe
如何应对m
,否则您无法真正使用Maybe
- 它需要处理Nothing
那么也许你希望它有类型StateT (Maybe s) IO ()
?
您的代码的第二个逻辑问题(?)肯定是s
返回的interval
肯定不会被更改 - setInterval代码可能已被触发,直到javascript回到它的空闲循环。
多年来已经多次讨论过传递回调的一般问题,请参阅:
https://mail.haskell.org/pipermail/haskell-cafe/2007-July/028501.html http://andersk.mit.edu/haskell/monad-peel/ http://blog.sigfpe.com/2011/10/quick-and-dirty-reinversion-of-control.html
等