11

Gtk2Hを使用してアプリケーションを作成する方法を学ぼうとすると、イベント駆動型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

私のアプリケーションの状態は、ボタンが押された回数です。このような他の投稿を見ると、MVarまたはIORefに依存していますが、これは私には満足のいくものではないようです。将来、コードをリファクタリングして、状態が独自のコンテキストで動作するようにするためです。

ソリューションでは、次のようなステップ関数を使用してStateモナドを使用する必要があると思います。

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

しかし、その意味、上記のコードでそれを行う方法、またはそのモナドが私の問題の正しい解決策であるかどうかについてはわかりません。

4

1 に答える 1

7

基本的に2つのアプローチがあります。

  1. ある種のポインタを使用してください。これはあなたのIORefまたはMVarアプローチです。MonadState必要に応じて、これを-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. 制御の反転」スタイルのトリックを引き出します。数値を出力するコールバックを作成してから、より大きな数値を出力する新しいコールバックに置き換えます。

直接使用しようとするとStateStateTひどい時間を過ごすことになります。

于 2012-08-17T09:45:24.280 に答える