2016-08-12 29 views
1

這是我之前的一個後續問題:State and IO Monads如何從main啓動monad變壓器堆棧?

我的目標是爲文件創建一個簡單的文本編輯器。我已經有了一個Editor組件,它很好地封裝了底層數據結構上的所有編輯操作。

多虧了答案,我剛纔的問題,我可以修改我的程序,所以,我現在有一個很好的單子轉換堆棧:

type Session = StateT AppState (StateT Editor IO) 

AppState包含應用程序(當前打開的文件的全局狀態等等),而Editor代表應用程序編輯組件的內部狀態(插入符號位於...等)。我有一個功能是應用程序的主要驅動力:

eventLoop :: Session() 

到目前爲止好,但現在我不知道我其實可以從我main功能腳踏啓動我的變壓器棧? Main必須在我的堆棧的底部返回IO monad中的內容。我的猜測是,我必須初始化我AppState,然後做一些事情,如:

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

但我在哪裏初始化我Editor現在?

最主要的困惑我的是,重構之前,Editor只是的AppState成員:

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

,但現在它已經移出AppState,成爲變壓器堆棧上的兄弟姐妹一些。不應該Editor仍然是AppState的一部分,因爲修改它意味着修改整體狀態?

如何正確初始化我的Session同時使用AppStateEditor,然後從我的main運行它?

+0

在'StateT'裏面包裝'StateT'將需要一個尷尬的組合升降機來訪問正確的狀態。使用'StateT(AppState,EditorState)'(或者你自己的數據類型)會更好,所以你可以使用'MonadState'''''等。 –

回答

2

我怎麼能從我的主要功能實際啓動我的變壓器堆棧?

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

不應編輯器仍然屆時AppState的一部分,因爲修改它意味着要修改的整體狀況?

這取決於。

請記住,Monad Transformer的目的是以臨時方式擴展功能嗎?我的意思是,不用重寫現有的代碼庫,而是通過添加它。因此,如果您已經擁有編輯器和AppState的獨立API,只需使用變壓器堆棧將它們組合到另一個「圓頂」模塊中即可。

OTOH從最初的架構角度來看,AppState是一個包含編輯器(我將其命名爲EditorState)的數據結構。在這樣的CAS中,AppState的API應該封裝編輯器的API。「鏡頭」庫將幫助你處理這種複合數據結構(儘管我必須提到它有一個陡峭的學習曲線)。

+0

它又是你:) 謝謝,我能夠得到你的幫助一切工作。 我之前已經使用過鏡片,但我從未真正掌握過這個概念,並且我在下次嘗試刺穿這個主題時要慢一些。 – DeX3

+0

不客氣) –