Hatena::Grouphaskell

[ pred x | x <- "Ibtlfmm!ojllj" ] RSSフィード

2008-02-28

オブジェクトをモナド変換子に書き換える (1) 21:23

  • インスタンス変数のうち変化するものと変化しないものを書き出す
  • それぞれをまとめてdataを作る
data ImmutableFields = IF { ... } deriving (Show)
data MutableFields = MF { ... } deriving (Show)
  • 以下のようにnewtypeを定義
    • newtype deriving(id:illillli:20080217#p1)が必要
    • TとrunTは公開しない
    • 二回ラップしているからか、MonadTransはderivingがうまくいかない
newtype HogeT m a = T
  { runT :: ReaderT ImmutableFields (StateT MutableFields m) a
  } deriving
  ( Functor
  , Monad
  , MonadIO
  , MonadReader ImmutableFields
  , MonadState MutableFields
  )

instance MonadTrans HogeT where
  lift = T . lift . lift
    • 他に必要なモナドがあったら、変換子としてその都度mに要求する (試してない)
hoge :: (MonadFuga m) => SomeClassT m a
  • コンストラクタ代わりの関数を書く
    • パラメータはちゃんとtypeしておくこと
    • 元のnewにデフォルト引数があったら defaultHoge :: Hoge を作っておく
newHoge :: Count -> Name -> Hoge
  • ランナーを書く(IO込みの初期化があったらここでやる)
runHogeT :: (Monad m) => Hoge -> HogeT m a -> m (a, Hoge)
  • アクセサを書き直す
setSomeField = modify $ \fs -> fs { someField = x }
  • メソッドを書き直す
    • IOはliftIO $ do ...内で行う
  • エクスポートするのは以下のものだけ
    • HogeT ()
    • type各種
    • newHoge
    • runHoge, withHoge
    • アクセサ
    • メソッド

ここまでで一息。変化しないフィールドを分けているのはバグが減りそうなため。

この時点ですでにプログラムは書けるが、もうひと手間かけるとliftがうるさいのを減らすことができる。