2016-08-12 8 views
1

このような質問は私の前の質問と同じです:State and IO Monadsモナドトランススタックをメインからキックスタートする方法は?

私の目標は、ファイル用の簡単なテキストエディタを作成することです。私は既にEditorコンポーネントを持っています。このコンポーネントは、基礎となるデータ構造上のすべての編集アクションを素早くカプセル化します。

type Session = StateT AppState (StateT Editor IO) 

AppStateは、アプリケーション(現在開いているファイルのグローバルな状態を保持している:私は今、素敵なモナド変圧器スタックを持っているように、私の前の質問への回答に

おかげで、私は私のプログラムをリファクタリングすることができました、etc. ...)、Editorは、アプリケーションの編集コンポーネントの内部状態を表します(キャレットは、など)。私は実際に私のmain関数から私の変圧器スタックを、キックスタートできるかわからないが、今、これまでのところは良い

eventLoop :: Session() 

:私は、アプリケーションのメインドライバである機能を持っていますか?メインは私のスタックの根底にあるIOモナドに何かを返さなければなりません。

main = do 
    let initialAppState = ... 
    return $ runStateT eventLoop initialAppState 

しかし、私は今、私のEditorを初期化します。ここで私の推測では、私は私のAppStateを初期化する必要があり、その後のような何かをするということですか?

data AppState = { editor :: Editor , ... } 

が、今それがAppStateの外に移動したと変圧器スタック上の兄弟の多少になる:

私を混乱主なものは、リファクタリングの前に、Editorは単にAppStateのメンバーであったということです。 EditorはまだAppStateに属していてはなりません。

SessionAppStateEditorの両方で正しく初期化してから、mainから実行しますか?

+0

'StateT'の中に' StateT'をラップするには、正しい状態にアクセスするためのリフトの厄介な組み合わせが必要です。 'StateSt(AppState、EditorState)'(または独自のデータ型)を使うのが良いでしょう。そうすれば、MonadStateの 'get'などを持ち上げなくても使うことができます。 –

答えて

2

どのようにして私のトランスからのスタックを実際にメイン機能からキックスタートさせることができますか?変更することは、全体的な状態を変更を意味するので

main = 
    flip evalStateT initialAppState $ 
    flip evalStateT initialEditorState $ 
    eventLoop 
    where 
    initialAppState = 
     error "Define me" 
    initialEditorState = 
     error "Define me" 

エディタはまだAppStateの一部ではないでしょうか?

によって異なります。

Monad Transformerの目的は、アドホックな方法で機能を拡張することです。アドホックでは、既存のコードベースを書き直すことなく、それを追加することで意味します。したがって、すでにEditorとAppStateのAPIを分離している場合は、トランススタックを使用して別の「ドーム」モジュールでそれらを結合する方が簡単です。

OTOHは、最初のアーキテクチャの観点から、AppStateはEditor(私はそれをEditorStateと名付ける)を含むデータ構造です。このような場合、AppStateのAPIはEditorのAPIをカプセル化する必要があります。「レンズ」ライブラリは、このような複合データ構造で作業するのに役立ちます(ただし、学習曲線は急峻です)。

+0

もう一度です:) ありがとう、私はあなたの助けを借りてすべてを得ることができました。 私はすでにレンズを一度も使用していませんが、実際にはコンセプトを理解したことはありません。 – DeX3

+0

ようこそ) –

関連する問題