假設我有兩個單子變壓器Precomposing單子變壓器
T1 :: (* -> *) -> * -> *
T2 :: (* -> *) -> * -> *
與實例
instance MonadTrans T1
instance MonadTrans T2
和一些
X :: (((* -> *) -> * -> *) -> ((* -> *) -> * -> *) -> * -> *)
如
newtype X t1 t2 a b = X { x :: t1 (t2 a) b }
爲此我想沿線
instance (MonadTrans t1, MonadTrans t2) => MonadTrans (X t1 t2) where
lift = X . lift . lift
定義的東西,這樣我可以用lift
解除m a
到X T1 T2 m a
?
這裏的問題似乎是,lift
對一些monad Monad m => m a
採取行動,我不能保證在中間步驟中生產。但是這對我來說很困惑。我提供了一個lift
的實現,所以我可以假設我有Monad m => m a
,所以我應用最右邊的lift
並得到T1 m a
,我對此一無所知,但是不應該暗示T1 m
是Monad
?如果不是,爲什麼我不能簡單地將此添加到我的實例的約束中
instance (MonadTrans t1
, MonadTrans t2
, Monad (t2 m)) => MonadTrans (X t1 t2) where ...
這也不起作用。我有一個直覺,通過上述我說:「應該有t1
,t2
,m
,使... ...」,這太弱,無法證明X t1 t2
是變壓器(適用於任何/所有Monad m
)。但是對我來說,這仍然沒有什麼意義,一個有效的monad變壓器在應用於monad時能產生一個非monad嗎?如果不是,我應該能夠脫離MonadTrans (X t1 t2)
的實例。
有沒有什麼辦法可以做到這一點,但沒有理由說明它無法完成(理論上還是對當前編譯器支持的限制)。
會暗示對應於除
instance (MonadTrans t, Monad m) => Monad (t m) where
return = lift . return
a >>= b = ... # no sensible generic implementation
其他任何這將覆蓋其他實例/無法提供具體的綁定?難道這不能解決一些間接問題嗎?製作returnT :: Monad m => a -> t m a
和MonadTrans
bindT :: Monad m => t m a -> (a -> t m b) -> t m b
一部分,這樣可以再寫入
instance MonadTrans (StateT s) where
lift = ...
returnT = ...
bindT = ...
...
instance (MonadTrans t, Monad m) => Monad (t m) where
return = returnT
a >>= b = a `bindT` b
這種情況下,目前不因重疊有效的,他們會不過是可行的,有用嗎?
謝謝!有沒有被添加的機會? – jakubdaniel
@ jd823592我對此表示懷疑。它會破壞太多的代碼 - 世界上的每個「MonadTrans」實例,包括第三方閉源代碼庫中的實例,都必須更改爲實現「transform」成員,這並不總是微不足道的 - 並且在實踐中「變革」並不是真正有用的,所以收益不會超過成本。 (我已經更新了我的答案。) –
但是由於沒有代碼真的使用這個特性,所以'transform'的默認定義會失敗。因爲它沒有被使用,所以它不會破壞代碼,並且變換器用於將東西從一個版本分解到另一個版本,這就是版本控制的好處:)因此,即便如此,變換器也沒有'transform':'(:)?當然標準變壓器會得到正確的實施。 – jakubdaniel