我試圖採用ExceptT a (StateT A M)
,對於某些具體類型A
和monad M
,並將它們包裹到我的新自定義monads中。整理Monads - 將monad變壓器的應用轉換爲新型monad
首先我確定了StateT A M
在其他環境中經常出現,因此我決定這將是最好的單獨包裝在一個單子M1
,然後包裝成ExceptT a M1
M2
。
期望的特性是使MonadState
M1
和M2
實例和類M
(讓我們假設它被稱爲MyMonadClass
)。 M2
也應該是MonadError
的實例。
首先,我開始用簡單的類型同義詞:
type MyState = StateT A M
type MyBranch a = ExceptT a MyState
轉念一想,我會首先繪製實例聲明(不執行實例)和多數民衆贊成在我第一次卡住了。 instance MonadState A (MyState)
似乎不是正確的語法。我以爲我將不得不創建newtype MyState' a = StateT a M
,然後type MyState = MyState A
(不要使用不必要的語言擴展)。
但是,一旦我開始將同義詞轉換爲newtype
聲明,我開始失去與StateT A M
和ExceptT ...
類型的連接。
newtype MyState' s a = MyState' { runMyState :: s -> (s, a) }
type MyState = MyState' A
newtype MyBranch e a = MyBranch { runMyBranch :: MyState (Either e a) }
現在已經實施的變壓器消失了,我想我正在嘗試做一些沒有多大意義的事情。所以我的問題是:如何正確地將這種行爲包裝到新的複合單體中,從而能夠訪問下面的圖層,從而避免不必要的提升,保持事物清晰和組織良好。
非常感謝你,這是一個偉大的答案。我可以以某種方式沒有像'GeneralizedNewtypeDeriving'這樣的語言擴展嗎? – jakubdaniel
@JakubDaniel當然,你可以手動編寫所有的實例。但是你不想(也可能會搞亂一個),因此是'GeneralizedNewtypeDeriving'。 – Cirdec
要查看得到的實際代碼,請在GHCi中運行命令':set -ddump-deriv',它會向您顯示GHC慷慨地爲您編寫的所有代碼。 'data AB = A | B推導出Eq'dumps'實例GHC.Classes.Eq Ghci5.AB其中(GHC.Classes。==)Ghci5.A Ghci5.A = GHC.Types.True; (GHC.Classes。==)Ghci5.B Ghci5.B = GHC.Types.True; (GHC.Classes。==)_ _ = GHC.Types.False' –