在Haste中为StateT monad写入间隔函数

时间:2015-09-25 08:02:02

标签: haskell monad-transformers ioref haste

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

1 个答案:

答案 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