Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
811 views
in Technique[技术] by (71.8m points)

haskell - How to deal with application state in Gtk2Hs

Trying to learn to write applications with Gtk2Hs I'm getting difficulties bridging the gap between the event driven Gtk2HS and the persistent state of my model. So to simplify, lets say that I have this simple application

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

and the state of my application is how many times the button has been pressed. Seeing other posts like this they rely on MVars or IORefs which do not seem satisfactory to me, because in the future maybe I will want to refactor the code so the state lives on its own context.

I think that the solution should use the State monad using a step function like:

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

but I'm not sure about the implications, how to do that in the above code or even if that monad is the right solution to my problem.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There's basically two approaches:

  1. Use a pointer of some kind. This is your IORef or MVar approach. You can hide this behind a MonadState-like interface if you like:

    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. Pull an "inversion of control" style trick. Write a callback that prints a number, then replaces itself with a new callback that prints a higher number.

If you try to use State or StateT directly, you're gonna have a bad time.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...