1

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

4

1 回答 1

3

您传递给 FFIjsInterval的 IO 操作只是一个普通的 IO 操作。如果您使用执行该操作,runStateT您只是在运行一点 'local' 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如何应对 a 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

等等

于 2015-09-25T09:41:32.043 回答