如何处理Gtk2Hs中的应用程序状态

时间:2012-08-17 09:01:53

标签: haskell state-monad gtk2hs

尝试学习使用Gtk2Hs编写应用程序我遇到了困难,弥合了事件驱动的Gtk2HS与模型的持久状态之间的差距。所以为了简化,让我说我有这个简单的应用程序

module Main where

import Graphics.UI.Gtk
import Control.Monad.State

main = do
    initGUI
    window <- windowNew
    button <- buttonNew
    set button [buttonLabel := "Press me"]
    containerAdd window button

    -- Events
    onDestroy window mainQuit
    onClicked button (putStrLn ---PUT MEANINGFUL CODE HERE---)

    widgetShowAll window
    mainGUI

我的应用程序状态是按下按钮的次数。看到像this这样的其他帖子,他们依赖于MVars或IORefs,这对我来说似乎并不令人满意,因为将来我可能想要重构代码,以便状态存在于自己的上下文中。

我认为解决方案应该使用状态monad使用步骤函数,如:

State $ \s -> ((),s+1)

但我不确定其含义,如何在上面的代码中执行此操作,或者即使该monad是解决我问题的正确方法。

1 个答案:

答案 0 :(得分:6)

基本上有两种方法:

  1. 使用某种指针。这是您的IORefMVar方法。如果您愿意,可以将此隐藏在类似MonadState的界面后面:

    newtype GtkT s m a = GtkT { unGtkT :: ReaderT (IORef s) m a } deriving (Functor, Applicative, Monad, MonadIO)
    runGtkT = runReaderT . unGtkT
    
    instance MonadIO m => MonadState s (GtkT s m) where
        get   = GtkT (ask >>= liftIO . readIORef)
        put s = GtkT (ask >>= liftIO . flip writeIORef s)
    
  2. 拉出“inversion of control”样式技巧。编写一个打印数字的回调,然后用一个打印更多数字的新回调替换自己。

  3. 如果您尝试直接使用StateStateT,那么您将度过难关。