在三便士中使用 IORef

Using IORef in threepenny gui

我试图在 threepenny-gui 中设置一个 IORef,但我无法让它工作。在我的应用程序中,IORef 本身会更复杂并且不会显示本身 - 但这个示例演示了我认为的问题。

这是我的尝试:

testIORef2 :: IORef String -> Window -> UI ()
testIORef2 ref window = void $ do
    return window # set title "Test IORef"

    inCell <- UI.input
    outCell   <- UI.input

    getBody window #+ [
            column [
                grid [[string " In cell::", element inCell]
                     ,[string "Out cell::"  , element outCell  ]]
            , string "Cells should update while typing."
            ]]

    -- When value changes write to IORef
    on  UI.valueChange inCell $ \_ -> do
        inValue <- get value inCell
        liftIO $ writeIORef ref inValue    

    -- Read the IORef
    refVal <- liftIO $ readIORef ref

    -- Behaviour which holds the string value in the input cell
    inValue <- stepper "0" $ UI.valueChange inCell
    -- Behaviour which holds the value in the ref
    let outValue = (const refVal) <$> inValue

    -- Set the value of the output cell to the outValue
    element outCell # sink value outValue

代码可以正常工作,但 outValue 不是最新的。

如何修复它以便及时更新。此外,欢迎对代码进行任何改进。

谢谢。

我不是 threepenny-gui 的专家,但这是我的猜测。

您在外部 on 事件处理程序编写的代码仅执行一次。因此,您希望在 outValue 更新 内包含 所述处理程序,例如

-- When value changes write to IORef
on  UI.valueChange inCell $ \_ -> do
    inValue <- get value inCell
    liftIO $ writeIORef ref inValue    
    ... -- compute outValue
    element outCell # sink value outValue

你写的代码可能不是你想要做的。行

let outValue = (const refVal) <$> inValue

指定outValue是一个Behavior,其值是常量,等于refValue。反过来,后面的值是从

中得到的
refVal <- liftIO $ readIORef ref

这意味着它是 IORef 在这个时间点存储在 UI monad 中的值。


当使用IORef时,你想在发生变化时读取引用的值,并使用这个值来修改UI内容,例如这样:

on  UI.valueChange inCell $ \_ -> do
    inValue  <- get value inCell
    liftIO $ writeIORef ref inValue
    outValue <- liftIO $ readIORef ref    
    element outCell # set value outValue

出于一致性(操作顺序)的原因,不建议使用 IORef 作为 Behavior 的来源——它要么是后者,要么是前者。