0

考慮下面的代碼片斷任意單子變壓器堆棧變量

import Control.Monad.Trans 
import Control.Monad.Trans.Except 
import Control.Monad.Trans.State 

newtype MyTransT m a = MyTransT (m a) 

foo :: (MonadTrans t, Monad (t (Either e))) => MyTransT (t (Either e)) a -> a 
foo = undefined 

bar :: MyTransT (StateT Int (Either e)) a 
bar = undefined 

baz :: MyTransT (StateT Int (StateT Int (Either e))) a 
baz = undefined 

x = foo bar -- works 

y = foo baz -- doesn't work 

在本質上,我想創建它接受一個單子變壓器堆的功能,具有指定的堆疊的頂部和底部,而中間可以是任何東西。

抓我的頭一會兒,爲什麼foo baz正在與Couldn't match type ‘StateT Int (Either e1)’ with ‘Either e0’拒絕後,它終於發生,我認爲在這種情況下,我是假設tStateT Int (StateT Int)這不僅不是一個MonadTrans,其無法正常打字/ kinded。

有什麼方法可以完成我正在嘗試做的事情,還是有時間嘗試不同的方法?

+0

你能舉出一些具體的例子,說明你希望'foo'在實踐中工作嗎? – ErikR

+0

想象一下你有一個'T'類型,它可以被認爲是'K'類型的'V'類型的容器。現在想象每個'V'也遵循這種模式。我想有'foo :: StateT V(t(E))a - > StateT T(ReaderT K(t(E或e)))a'。這將對'V'進行有狀態操作,並通過'T'將它們置於有'K'環境的有狀態操作。基本上是一個樹結構,我可以無限地向上和向下延伸,而無需更改現有的代碼。 – user2085282

+0

具體例子在這裏會更有幫助。隨意將它放在你的問題中,它會更容易閱讀。 – ErikR

回答

0

foo baz不輸入檢查的原因是因爲t不是Either e monad上的變換器 - 它是通過StateT Int (Either e) monad的變換器。

這裏是它是如何解析:

baz :: MyTransT (StateT Int (StateT Int (Either e))) a 
        \________/ \_____________________/ 
         t   m     a 

注意m的形式Either e

您可以創建一個新的變壓器,例如StateTIntStateTInt,寫 巴茲這樣的:

baz :: MyTransT (StateTIntStateInt (Either e)) a 

,然後鍵入檢查。例如:

type StateTIntStateTInt = StateT (Int,Int) 

baz' :: MyTransT (StateTIntStateTInt (Either e)) a 
baz' = undefined 

test = foo baz' 

但是,即使你解決的問題類型,我懷疑你會 要能寫函數foo

bar0 :: MyTransT (StateT Int (Either String)) Int 
bar0 = MyTransT $ lift $ Left "blather" 

什麼int值應foo bar0回報:考慮什麼應該爲bar這個特定的值返回 ?

+0

我意識到這一點,甚至在問題中指出。關鍵是'foo'應該能夠接受任意一堆變形金剛,因此爲每一種可能性創造一種新形式似乎不太可能。另外,'foo'的返回類型是一個佔位符,這個片段只是爲了演示這個問題。實際上,'foo'會返回一個與't(e或e)'相關的值 – user2085282