尝试学习使用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是解决我问题的正确方法。
答案 0 :(得分:6)
基本上有两种方法:
使用某种指针。这是您的IORef
或MVar
方法。如果您愿意,可以将此隐藏在类似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)
拉出“inversion of control”样式技巧。编写一个打印数字的回调,然后用一个打印更多数字的新回调替换自己。
如果您尝试直接使用State
或StateT
,那么您将度过难关。