作為練習,我一直在重新實作一些常見的 monad 及其相應的轉換器;以下是我定義的一些型別:
newtype Writer w a = Writer { runWriter :: (w, a) }
newtype WriterT w m a = WriterT { runWriterT :: m (Writer w a) }
newtype Maybe a = Just a | Nothing
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
當我得到它時,一個變壓器將一個單子“包裹”在一個外部單子中m;按照這種直覺,我嘗試ReaderT以類似的方式定義變壓器:
newtype Reader r a = Reader { runReader :: r -> a }
newtype ReaderT r m a = ReaderT { runReaderT :: m (Reader r a) }
但是,我在實作它的 monad 實體時遇到了困難。通過查看庫定義,ReaderT我看到它被定義為
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
除了它不使用Reader(可以用 來定義ReaderT)這一事實之外,為什么它被定義為r -> m a而不是m (r -> a)?我認為它應該用外部單子獲取而不是包裹內部Reader(即)r -> amm (r -> a)r -> m a
uj5u.com熱心網友回復:
m (r -> a)意味著您:
首先在 monad 中執行一些操作,然后,
動作完成后,對 reader 值進行純計算。
但是您需要能夠使用ask:
ask :: Monad m => ReaderT r m r
使用ask,您可以:
首先讀取值,
然后執行一些單子動作,作用于值。
這就是為什么r -> m a有意義和m (r -> a)沒有意義的原因。
如果有幫助,請將此視為與 writer monad 的“對稱”。對于 writer monad,monad 在外部,結果在內部。對于 reader monad,輸入在外部,monad 在內部。這種對稱性出現了很多。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/493306.html
