有幾個問題(例如this和this)詢問 Haskell 中的每個 monad(除了 IO)是否都有相應的 monad 轉換器。現在我想問一個補充問題。是否每個 monad 都只有一個變壓器(或者像 IO 一樣沒有),還是可以有多個變壓器?
一個反例是兩個 monad 轉換器,它們在應用于身份 monad 時會產生行為相同的 monad,但在應用于其他一些 monad 時會產生不同行為的 monad。如果答案是 monad 可以有多個轉換器,我希望有一個盡可能簡單的 Haskell 示例。這些不一定是真正有用的轉換器(盡管那會很有趣)。
鏈接問題中的一些答案似乎表明單子可以有多個變壓器。但是,除了類別的基本定義之外,我對類別理論知之甚少,所以我不確定它們是否是這個問題的答案。
uj5u.com熱心網友回復:
這是唯一性的反例的一個想法。我們知道,一般來說,monad 不會組合......但我們也知道,如果有適當的swap操作,您可以組合它們[1]!讓我們為可以與自己交換的 monad 創建一個類。
-- | laws (from [1]):
-- swap . fmap (fmap f) = fmap (fmap f) . swap
-- swap . pure = fmap pure
-- swap . fmap pure = pure
-- fmap join . swap . fmap (join . fmap swap) = join . fmap swap . fmap join . swap
class Monad m => Swap m where
swap :: m (m a) -> m (m a)
instance Swap Identity where swap = id
instance Swap Maybe where
swap Nothing = Just Nothing
swap (Just Nothing) = Nothing
swap (Just (Just x)) = Just (Just x)
然后我們可以構建一個 monad 轉換器,它與自身組成一個 monad,如下所示:
newtype Twice m a = Twice (m (m a))
希望它應該是顯而易見pure的(<$>)。(>>=)我將定義,而不是定義join,因為我認為發生了什么更明顯;(>>=)可以從中得出。
instance Swap m => Monad (Twice m) where
join = id
. Twice -- rewrap newtype
. fmap join . join . fmap swap -- from [1]
. runTwice . fmap runTwice -- unwrap newtype
instance MonadTrans Twice where lift = Twice . pure
我沒有檢查是否在所有情況下都lift遵守MonadTrans法律Swap,但我確實檢查了它們的Identityand Maybe。
現在,我們有
IdentityT Identity ~= Identity ~= Twice Identity
IdentityT Maybe ~= Maybe !~= Twice Maybe
這表明這IdentityT不是用于生產的獨特單子變壓器Identity。
[1] Mark P. Jones 和 Luc Duponcheel 組成單子
uj5u.com熱心網友回復:
恒等單子至少有兩個單子轉換器:恒等單子轉換器和共密度單子轉換器。
newtype IdentityT m a = IdentityT (m a)
newtype Codensity m a = Codensity (forall r. (a -> m r) -> m r)
實際上,考慮到Codensity Identity,forall r. (a -> r) -> r與 同構a。
這些單子變換器是完全不同的。一個例子是“括號”可以定義為一個單子動作Codensity:
bracket :: Monad m => m () -> m () -> Codensity m ()
bracket before after = Codensity (\k -> before *> k () *> after)
而將該簽名轉換為IdentityT沒有多大意義
bracket :: Monad m => m () -> m () -> IdentityT m () -- cannot implement the same functionality
其他例子可以從 continuation/codensity monad 的變體中類似地找到,盡管我還沒有看到一個通用的方案。
state monad 對應于 state monad 轉換器和 和 的Codensity組成ReaderT:
newtype StateT s m a = StateT (s -> m (s, a))
newtype CStateT s m a = CStateT (Codensity (ReaderT s m) a)
串列 monad 至少對應三個 monad 轉換器,不包括錯誤的一個:
newtype ListT m a = ListT (m (Maybe (a, ListT m a))) -- list-t
newtype LogicT m a = LogicT (forall r. (a -> m r -> m r) -> m r -> m r) -- logict
newtype MContT m a = MContT (forall r. Monoid r => (a -> m r) -> m r))
前兩個可以分別在包list-t(也在管道中的等效形式)和logict中找到。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/493312.html
